package com.mmd.manage.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import com.google.common.base.Splitter;
import com.mmd.bean.CODE;
import com.mmd.bean.UserLoginContext;
import com.mmd.common.bean.Traces;
import com.mmd.common.bean.TracesVo;
import com.mmd.common.entity.*;
import com.mmd.common.enums.*;
import com.mmd.common.mapper.MmdQuotationDetailHistoryMapper;
import com.mmd.common.mapper.MmdQuotationHistoryMapper;
import com.mmd.exception.GameException;
import com.mmd.intercepter.AdminInterceptor;
import com.mmd.manage.dao.*;
import com.mmd.manage.service.ModeMYCService;
import com.mmd.manage.service.OrderService;
import com.mmd.manage.service.PullLogisticsInfoService;
import com.mmd.manage.vo.*;
import com.mmd.utils.DateUtil;
import com.mmd.utils.UniqueNoUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.PrintSetup;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author cyq
 * @Date 2019/8/29 20:20
 * @Description
 **/
@Service
public class OrderServiceImpl implements OrderService {
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    //美国国家的ID集合
    private List<Long> usCountryIdList = Arrays.asList(1l,5l,6l,7l);
    //欧洲国家的ID集合
    private List<Long> europeCountryIdList = Arrays.asList(2l,8l,9l,10l,11l,12l);

    private List<BigDecimal> otherKgList = Arrays.asList(
                                            new BigDecimal(21),
                                            new BigDecimal(46),
                                            new BigDecimal(71),
                                            new BigDecimal(101),
                                            new BigDecimal(301),
                                            new BigDecimal(501),
                                            new BigDecimal(1001));
    //ups红单的kg
    private List<BigDecimal> upsRedKgList = Arrays.asList(
                                            new BigDecimal(23),
                                            new BigDecimal(46),
                                            new BigDecimal(71),
                                            new BigDecimal(101),
                                            new BigDecimal(301),
                                            new BigDecimal(501),
                                            new BigDecimal(1001));

    //海运的kg
    private List<BigDecimal> haiYunKgList = Arrays.asList(
                                            new BigDecimal(100),
                                            new BigDecimal(301),
                                            new BigDecimal(501),
                                            new BigDecimal(1001));

    @Autowired
    private MmdOrderDao mmdOrderDao;
    @Autowired
    private MmdOrderDetailDao mmdOrderDetailDao;
    @Autowired
    private SuOrderDao suOrderDao;
    @Autowired
    private SuOrderDetailDao suOrderDetailDao;
    @Autowired
    private UserDao userDao;
    @Autowired
    private MmdQuotationDao mmdQuotationDao;
    @Autowired
    private MmdQuotationHistoryMapper mmdQuotationHistoryMapper;
    @Autowired
    private MmdQuotationDetailHistoryMapper mmdQuotationDetailHistoryMapper;
    @Autowired
    private MmdQuotationDetailDao mmdQuotationDetailDao;
    @Autowired
    private MmdQuotationHscodeDao mmdQuotationHscodeDao;
    @Autowired
    private MmdLogisticsDao mmdLogisticsDao;
    @Autowired
    private MmdOrderLogisticsDao mmdOrderLogisticsDao;
    @Autowired
    private PullLogisticsInfoService pullLogisticsInfoService;
    @Autowired
    private MmdOrderProductDao mmdOrderProductDao;
    @Autowired
    private MmdFbaDao mmdFbaDao;
    @Autowired
    private MmdPostcodeDao mmdPostcodeDao;
    @Autowired
    private AreaDao areaDao;
    @Autowired
    private MmdSupplierDao mmdSupplierDao;
    @Autowired
    private MmdRouteDao mmdRouteDao;
    @Autowired
    private RouteDetailDao routeDetailDao;
    @Autowired
    private RouteHscodeDao routeHscodeDao;
    @Autowired
    private MmdBillRecordDao mmdBillRecordDao;
    @Autowired
    private ModeMYCService modeMYCService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addOrder(OrderEo eo) {
        logger.info("入参===>{}", JSON.toJSONString(eo));
        this.checkParam(eo);
        if (!StringUtils.isBlank(eo.getOrderNo())) {

            MmdOrder mmdOrder = mmdOrderDao.selectByPrimaryKey(eo.getOrderNo());
            if (mmdOrder != null) {
                throw new GameException(new CODE(9999, "fba单号重复，请在fba单号后面添加序号"));
            }
        }
        MmdOrder order = new MmdOrder();
        BeanUtils.copyProperties(eo, order);
        order.setFbaDepotNo(eo.getFbaDepotName());
        if (StringUtils.isBlank(eo.getOrderNo())) {
            String orerNo = UniqueNoUtils.next(UniqueNoUtils.UniqueNoType.O);
            order.setOrderNo(orerNo);
        } else {
            order.setOrderNo(eo.getOrderNo());
        }
        order.setBatchNo(order.getOrderNo());
        order.setOriginCountry("CN");
        if ("ADD".equals(eo.getFlag())) {
            order.setCreateTime(new Date());
            order.setStatus(StatusEnums.WAITAUDIT.getCode());
        } else {
            order.setCreateTime(new Date());
            order.setStatus(StatusEnums.SAVE.getCode());
        }
        order.setUid(AdminInterceptor.getUserLoginContext().getUid());

        MmdQuotation mmdQuotation = mmdQuotationDao.selectQuotationByRouteNo(eo.getRouteNo());
        if (mmdQuotation == null){
            throw new GameException(new CODE(9999, "没有匹配的报价单"));
        }
        order.setQuotationHistoryId(mmdQuotationHistoryMapper.getLastHistoryId(mmdQuotation.getQuotationNo()));
        order.setSingleOperatFee(mmdQuotation.getSingleOperatFee());
        order.setSingleDeclareFee(mmdQuotation.getSingleDeclareFee());
        order.setZgFee(mmdQuotation.getZgFee());

        int number = mmdFbaDao.getFbaNumberByPostcode(eo.getFbaPostcode());
        logger.info("orderNo:{}, fba number:{}",order.getOrderNo(),number);
        if (number > 0) {
            MmdPostcode mmdPostcode = mmdPostcodeDao.selectByPrimaryKey(eo.getFbaPostcode());
            if (mmdPostcode == null) {
                throw new GameException(new CODE(9999, "无效的邮编"));
            }
            order.setDestinationCountryId(mmdPostcode.getAreaId());
            order.setDestinationCountry(mmdPostcode.getAreaName());
        }else{
            //如果目的国是美国，则根据邮编开头第一位数字来判断是美国东岸、美国西岸和美国中部
            if (eo.getDestinationCountryId() == 1){
                if (eo.getFbaPostcode().startsWith("0") || eo.getFbaPostcode().startsWith("1") || eo.getFbaPostcode().startsWith("2") || eo.getFbaPostcode().startsWith("3") ){
                    //美国东岸
                    order.setDestinationCountryId(7l);
                    order.setDestinationCountry("美国东岸");
                }else if (eo.getFbaPostcode().startsWith("4") || eo.getFbaPostcode().startsWith("5") || eo.getFbaPostcode().startsWith("6") || eo.getFbaPostcode().startsWith("7")){
                    //美国中部
                    order.setDestinationCountryId(6l);
                    order.setDestinationCountry("美国中部");
                }else if (eo.getFbaPostcode().startsWith("8") || eo.getFbaPostcode().startsWith("9")){
                    //美国中部
                    order.setDestinationCountryId(5l);
                    order.setDestinationCountry("美国西岸");
                }
            }

            //如果目的国是加拿大，则根据邮编开头第一位数字来判断是温哥华V、渥太华K、卡尔加里T、多伦多M/L
            if (eo.getDestinationCountryId() == 15 && "N".equals(order.getIsAmazonFba())){
                if (eo.getFbaPostcode().startsWith("V")){
                    //温哥华
                    order.setDestinationCountryId(17l);
                    order.setDestinationCountry("温哥华");
                }else if (eo.getFbaPostcode().startsWith("K")){
                    //渥太华YOW1
                    order.setDestinationCountryId(20l);
                    order.setDestinationCountry("渥太华YOW1");
                }else if (eo.getFbaPostcode().startsWith("T")){
                    //卡尔加里YYC
                    order.setDestinationCountryId(16l);
                    order.setDestinationCountry("卡尔加里YYC");
                }else if (eo.getFbaPostcode().startsWith("M") || eo.getFbaPostcode().startsWith("L")){
                    //多伦多YYZ
                    order.setDestinationCountryId(18l);
                    order.setDestinationCountry("多伦多YYZ");
                }
            }
        }
        order.setChooseSup(YesNoEnums.NO.getCode());

        //配置装箱单
        List<MmdOrderDetailEo> mmdOrderDetailEos = JSON.parseArray(eo.getBoxDetails(), MmdOrderDetailEo.class);
        if (CollectionUtils.isEmpty(mmdOrderDetailEos)) {
            throw new GameException(new CODE(9999, "请填写装箱单"));
        }

        List<MmdOrderProduct> allOrderProduct = new ArrayList<>();
        for (MmdOrderDetailEo mmdOrderDetailEo : mmdOrderDetailEos) {
            List<MmdOrderProduct> mmdOrderProduct = JSON.parseArray(mmdOrderDetailEo.getProductEo(), MmdOrderProduct.class);
            allOrderProduct.addAll(mmdOrderProduct);
        }
        //计算附加费
        order.setAttachFee(this.calculateAttachFee(mmdQuotation.getQuotationNo(), allOrderProduct));

        //计费重量
        order.setChargedWeight(this.calculateChargedWeight(order, mmdOrderDetailEos, mmdQuotation));
        //计费单价
        if (!"9".equals(mmdQuotation.getChannelNo())) {
            order.setChargedPrice(this.calculateUnitPrice(order.getChargedWeight(), order, mmdQuotation));
        }else {
            order.setChargedPrice(this.calculateCbmUnitPrice(order.getChargedWeight(), order, mmdQuotation));
        }
        //计算订单的总价
        order.setTotalFee(this.calculateTotalFee(order, mmdQuotation));
        order.setIsSplit(YesNoEnums.NO.getCode());
        order.setIsDelete(0);
        mmdOrderDao.insert(order);
        for (MmdOrderDetailEo mmdOrderDetail : mmdOrderDetailEos) {
            logger.info("详情入参===>{}", JSON.toJSONString(mmdOrderDetail));
            //校验产品详情参数
            checkDetail(mmdOrderDetail);
            mmdOrderDetail.setPkgNo(UniqueNoUtils.next(UniqueNoUtils.UniqueNoType.pkg));
            mmdOrderDetail.setCreateTime(new Date());
            mmdOrderDetail.setOrderNo(order.getOrderNo());
            mmdOrderDetailDao.insert(mmdOrderDetail);

            List<MmdOrderProduct> mmdOrderProduct = JSON.parseArray(mmdOrderDetail.getProductEo(), MmdOrderProduct.class);
            if (CollectionUtils.isEmpty(mmdOrderProduct)) {
                throw new GameException(new CODE(9999, "请填写商品信息"));
            }
            for (MmdOrderProduct orderProduct : mmdOrderProduct) {
                logger.info("商品入参===>{}", JSON.toJSONString(orderProduct));
                checkProduct(orderProduct);

                orderProduct.setBoxNo(mmdOrderDetail.getBoxNo());
                orderProduct.setPkgNo(mmdOrderDetail.getPkgNo());
                orderProduct.setCreateTime(new Date());
                orderProduct.setOrderNo(order.getOrderNo());
                orderProduct.setPid(UniqueNoUtils.next(UniqueNoUtils.UniqueNoType.P));
                orderProduct.setIsUserShow(1);
                orderProduct.setIsAdminAndSupplyShow(1);
                orderProduct.setIsAdminModifyAfter(0);
                mmdOrderProductDao.insert(orderProduct);
            }

        }
        return true;
    }

    @Override
    @Transactional
    public boolean modifyOrder(OrderEo eo) {
        MmdOrder order1 = mmdOrderDao.selectByPrimaryKey(eo.getOrderNo());
        if (order1 == null) {
            throw new GameException(new CODE(9999, "订单不存在"));
        }
        this.checkParam(eo);
        MmdOrder order = new MmdOrder();
        BeanUtils.copyProperties(eo, order);
        order.setFbaDepotNo(eo.getFbaDepotName());
        order.setOriginCountry("CN");
        if ("ADD".equals(eo.getFlag())) {
            order.setCreateTime(new Date());
            order.setStatus(StatusEnums.WAITAUDIT.getCode());
        } else {
            order.setStatus(StatusEnums.SAVE.getCode());
        }
        order.setIsSplit(order1.getIsSplit());
        order.setUid(AdminInterceptor.getUserLoginContext().getUid());
        MmdQuotation mmdQuotation = mmdQuotationDao.selectQuotationByRouteNo(eo.getRouteNo());
        if (mmdQuotation == null){
            throw new GameException(new CODE(9999, "没有匹配的报价单"));
        }
        order.setSingleOperatFee(mmdQuotation.getSingleOperatFee());
        order.setSingleDeclareFee(mmdQuotation.getSingleDeclareFee());
        order.setZgFee(mmdQuotation.getZgFee());

        int number = mmdFbaDao.getFbaNumberByPostcode(eo.getFbaPostcode());
        logger.info("orderNo:{}, fba number:{}",order.getOrderNo(),number);
        if (number > 0) {
            MmdPostcode mmdPostcode = mmdPostcodeDao.selectByPrimaryKey(eo.getFbaPostcode());
            order.setDestinationCountryId(mmdPostcode.getAreaId());
            order.setDestinationCountry(mmdPostcode.getAreaName());
        }else{
            //如果目的国是美国，则根据邮编开头第一位数字来判断是美国东岸、美国西岸和美国中部
            if (eo.getDestinationCountryId() == 1){
                if (eo.getFbaPostcode().startsWith("0") || eo.getFbaPostcode().startsWith("1") || eo.getFbaPostcode().startsWith("2") || eo.getFbaPostcode().startsWith("3") ){
                    //美国东岸
                    order.setDestinationCountryId(7l);
                    order.setDestinationCountry("美国东岸");
                }else if (eo.getFbaPostcode().startsWith("4") || eo.getFbaPostcode().startsWith("5") || eo.getFbaPostcode().startsWith("6") || eo.getFbaPostcode().startsWith("7")){
                    //美国中部
                    order.setDestinationCountryId(6l);
                    order.setDestinationCountry("美国中部");
                }else if (eo.getFbaPostcode().startsWith("8") || eo.getFbaPostcode().startsWith("9")){
                    //美国中部
                    order.setDestinationCountryId(5l);
                    order.setDestinationCountry("美国西岸");
                }
            }

            //如果目的国是加拿大，则根据邮编开头第一位数字来判断是温哥华V、渥太华K、卡尔加里T、多伦多M/L
            if (eo.getDestinationCountryId() == 15 && "N".equals(order.getIsAmazonFba())){
                if (eo.getFbaPostcode().startsWith("V")){
                    //温哥华
                    order.setDestinationCountryId(17l);
                    order.setDestinationCountry("温哥华");
                }else if (eo.getFbaPostcode().startsWith("K")){
                    //渥太华YOW1
                    order.setDestinationCountryId(20l);
                    order.setDestinationCountry("渥太华YOW1");
                }else if (eo.getFbaPostcode().startsWith("T")){
                    //卡尔加里YYC
                    order.setDestinationCountryId(16l);
                    order.setDestinationCountry("卡尔加里YYC");
                }else if (eo.getFbaPostcode().startsWith("M") || eo.getFbaPostcode().startsWith("L")){
                    //多伦多YYZ
                    order.setDestinationCountryId(18l);
                    order.setDestinationCountry("多伦多YYZ");
                }
            }
        }

        //配置装箱单
        List<MmdOrderDetailEo> mmdOrderDetailEos = JSON.parseArray(eo.getBoxDetails(), MmdOrderDetailEo.class);
        if (CollectionUtils.isEmpty(mmdOrderDetailEos)) {
            throw new GameException(new CODE(9999, "请填写装箱单"));
        }

        //所有的商品
        List<MmdOrderProduct> allOrderProduct = new ArrayList<>(10);
        for (MmdOrderDetailEo mmdOrderDetailEo : mmdOrderDetailEos) {
            List<MmdOrderProduct> mmdOrderProduct = JSON.parseArray(mmdOrderDetailEo.getProductEo(), MmdOrderProduct.class);
            mmdOrderProduct.stream().forEach(pro -> allOrderProduct.add(pro));
        }
        //计费重量
        order.setChargedWeight(this.calculateChargedWeight(order, mmdOrderDetailEos, mmdQuotation));

        //没进行过分单才重新计算附加费和单价
        if (YesNoEnums.NO.getCode().equals(order.getIsSplit())) {
            //附加费
            order.setAttachFee(this.calculateAttachFee(mmdQuotation.getQuotationNo(), allOrderProduct));
            //计费单价
            if (!"9".equals(mmdQuotation.getChannelNo())) {
                order.setChargedPrice(this.calculateUnitPrice(order.getChargedWeight(), order, mmdQuotation));
            }else {
                order.setChargedPrice(this.calculateCbmUnitPrice(order.getChargedWeight(), order, mmdQuotation));
            }
        } else {
            order.setAttachFee(order1.getAttachFee());
            order.setChargedPrice(order1.getChargedPrice());
        }
        //计算订单的总价
        order.setTotalFee(this.calculateTotalFee(order,mmdQuotation));
        mmdOrderDao.updateByPrimaryKeySelective(order);

        mmdOrderDetailDao.deleteByOrderNo(eo.getOrderNo());
        mmdOrderProductDao.deleteByOrderNo(eo.getOrderNo());
        for (MmdOrderDetailEo mmdOrderDetail : mmdOrderDetailEos) {
            //校验产品详情参数
            checkDetail(mmdOrderDetail);
//            if (StringUtils.isBlank(mmdOrderDetail.getPkgNo())) {
            mmdOrderDetail.setPkgNo(UniqueNoUtils.next(UniqueNoUtils.UniqueNoType.pkg));
            mmdOrderDetail.setCreateTime(new Date());
            mmdOrderDetail.setOrderNo(order.getOrderNo());
            mmdOrderDetailDao.insert(mmdOrderDetail);
//            } else {
//                mmdOrderDetailDao.updateByPrimaryKeySelective(mmdOrderDetail);
//            }


            List<MmdOrderProduct> mmdOrderProduct = JSON.parseArray(mmdOrderDetail.getProductEo(), MmdOrderProduct.class);

            if (CollectionUtils.isEmpty(mmdOrderProduct)) {
                throw new GameException(new CODE(9999, "请填写商品信息"));
            }
            for (MmdOrderProduct orderProduct : mmdOrderProduct) {
                checkProduct(orderProduct);
//                if (StringUtils.isBlank(orderProduct.getPid())) {
                orderProduct.setBoxNo(mmdOrderDetail.getBoxNo());
                orderProduct.setPkgNo(mmdOrderDetail.getPkgNo());
                orderProduct.setCreateTime(new Date());
                orderProduct.setOrderNo(order.getOrderNo());
                orderProduct.setPid(UniqueNoUtils.next(UniqueNoUtils.UniqueNoType.P));
                orderProduct.setIsUserShow(1);
                orderProduct.setIsAdminAndSupplyShow(1);
                orderProduct.setIsAdminModifyAfter(0);
                mmdOrderProductDao.insert(orderProduct);
//                } else {
//                    mmdOrderProductDao.updateByPrimaryKeySelective(orderProduct);
//                }
            }

        }
        return true;
    }

    /**
     * 计算订单的总价
     *
     * @return
     */
    private BigDecimal calculateTotalFee(MmdOrder order,MmdQuotation mmdQuotation) {
        String mycName = "";
        if ("4".equals(mmdQuotation.getChannelNo())) {
            mycName = "DHL";
        }else if ("5".equals(mmdQuotation.getChannelNo()) || "6".equals(mmdQuotation.getChannelNo())) {
            mycName = "UPS";
        }else if ("7".equals(mmdQuotation.getChannelNo())) {
            mycName = "FedEx";
        }
        UserLoginContext userLoginContext = AdminInterceptor.getUserLoginContext();
        MmdModeMYC mmdModeMYC = null;
        if ("admin".equals(userLoginContext.getLevel())){
            mmdModeMYC = modeMYCService.getMYCByMycAndAdmin(mycName);
        }else{
            mmdModeMYC = modeMYCService.getMYCByMycAndUid(userLoginContext.getLevel(), userLoginContext.getUid(), mycName);
        }
        BigDecimal myc = BigDecimal.ZERO;
        if (mmdModeMYC != null && mmdModeMYC.getMyc() != null){
            myc = mmdModeMYC.getMyc();
        }
        BigDecimal oneAddMyc = new BigDecimal(1).add(myc);


        //单独清关总价=重量*单价*（1+燃油费）+重量*附加费+重量*中港+单票报关费+单票操作费
        //非单独清关总价=重量*单价*（1+燃油费）+重量*附加费+单票操作费
        BigDecimal totalFee = BigDecimal.ZERO;
        //海卡的不取整
        if (!"9".equals(mmdQuotation.getChannelNo())) {
            order.setChargedWeight(order.getChargedWeight().setScale(0, BigDecimal.ROUND_UP));
        }

        if (!StringUtils.isBlank(order.getIscog())) {
            //有报关文件，为单独清关
            totalFee = (order.getChargedWeight().multiply(order.getChargedPrice()).multiply(oneAddMyc))
                    .add(order.getChargedWeight().multiply(order.getAttachFee()))
                    .add(order.getChargedWeight().multiply(order.getZgFee()))
                    .add(order.getSingleDeclareFee()).add(order.getSingleOperatFee());
        } else {
            //非单独报关
            totalFee = (order.getChargedWeight().multiply(order.getChargedPrice()).multiply(oneAddMyc))
                    .add(order.getChargedWeight().multiply(order.getAttachFee()))
                    .add(order.getSingleOperatFee());
        }
        return totalFee;
    }

    /**
     * 计算订单的总价
     *
     * @return
     */
    private BigDecimal suCalculateTotalFee(SuOrder order) {
        //单独清关总价=重量*单价+重量*附加费+重量*中港+单票报关费+单票操作费
        //非单独清关总价=重量*单价+重量*附加费+单票操作费
        BigDecimal totalFee = BigDecimal.ZERO;
        order.setChargedWeight(order.getChargedWeight().setScale(0, BigDecimal.ROUND_UP));

        if (Objects.equals(order.getIscog(), YesNoEnums.YES.getCode())) {
            //单独清关
            totalFee = (order.getChargedWeight().multiply(order.getChargedPrice()))
                    .add(order.getChargedWeight().multiply(order.getAttachFee()))
                    .add(order.getChargedWeight().multiply(order.getZgFee()))
                    .add(order.getSingleDeclareFee()).add(order.getSingleOperatFee());
        } else {
            //非单独报关
            totalFee = (order.getChargedWeight().multiply(order.getChargedPrice()))
                    .add(order.getChargedWeight().multiply(order.getAttachFee()))
                    .add(order.getSingleOperatFee());
        }
        return totalFee;
    }

    /**
     * 计算订单的总价
     *
     * @return
     */
    private BigDecimal calculateSuTotalFee(SuOrder suOrder, MmdOrder mmdOrder) {
        //单独清关总价=重量*单价+重量*附加费+重量*中港+单票报关费+单票操作费
        //非单独清关总价=重量*单价+重量*附加费+单票操作费
        BigDecimal totalFee = BigDecimal.ZERO;
        suOrder.setChargedWeight(suOrder.getChargedWeight().setScale(0, BigDecimal.ROUND_UP));

        if (!StringUtils.isBlank(mmdOrder.getIscog())) {
            //有报关文件，为单独清关
            totalFee = (suOrder.getChargedWeight().multiply(suOrder.getChargedPrice()))
                    .add(suOrder.getChargedWeight().multiply(suOrder.getAttachFee()))
                    .add(suOrder.getChargedWeight().multiply(suOrder.getZgFee()))
                    .add(suOrder.getSingleDeclareFee()).add(suOrder.getSingleOperatFee());
        } else {
            //非单独报关
            totalFee = (suOrder.getChargedWeight().multiply(suOrder.getChargedPrice()))
                    .add(suOrder.getChargedWeight().multiply(suOrder.getAttachFee()))
                    .add(suOrder.getSingleOperatFee());
        }
        return totalFee;
    }

    /**
     * 计算当前子订单大的计费重量
     *
     * @return
     */
    private BigDecimal calculateChargedWeight(MmdOrder order, List<MmdOrderDetailEo> allOrderProduct, MmdQuotation mmdQuotation) {
        //计算当前子订单大的计费重量
        BigDecimal weightSum = BigDecimal.ZERO;
        BigDecimal volumeSum = BigDecimal.ZERO;
        //订单总重量
        for (MmdOrderDetailEo mmdOrderDetail : allOrderProduct) {
            weightSum = weightSum.add(mmdOrderDetail.getWeight());
            BigDecimal zl = BigDecimal.ZERO;
            if ("5".equals(mmdQuotation.getChannelNo()) || "6".equals(mmdQuotation.getChannelNo())) {
                zl = (mmdOrderDetail.getLength().multiply(mmdOrderDetail.getBreadth()).multiply(mmdOrderDetail.getHeight())).divide(new BigDecimal(5000), 2, RoundingMode.HALF_UP);
                if (mmdQuotation.getRouteNo().contains("UPS") ||mmdQuotation.getRouteName().contains("UPS")){
                    zl = halfUp5(zl);
                }
                //材积和重量哪个大，就以哪个为计算标准
                if (mmdOrderDetail.getWeight().compareTo(zl) > 0){
                    zl = mmdOrderDetail.getWeight();
                }
            } else if ("9".equals(mmdQuotation.getChannelNo())) {
                zl = (mmdOrderDetail.getLength().multiply(mmdOrderDetail.getBreadth()).multiply(mmdOrderDetail.getHeight())).divide(new BigDecimal(1000000), 3, RoundingMode.HALF_UP);
            }else {
                zl = (mmdOrderDetail.getLength().multiply(mmdOrderDetail.getBreadth()).multiply(mmdOrderDetail.getHeight())).divide(new BigDecimal(6000), 2, RoundingMode.HALF_UP);
                if (mmdQuotation.getRouteNo().contains("UPS") ||mmdQuotation.getRouteName().contains("UPS")){
                    zl = halfUp5(zl);
                }
                //材积和重量哪个大，就以哪个为计算标准
                if (mmdOrderDetail.getWeight().compareTo(zl) > 0){
                    zl = mmdOrderDetail.getWeight();
                }
            }
            //如果是美国海运/空运，计费重不足10kg，按10kg算
            if (usCountryIdList.contains(order.getDestinationCountryId()) && ("1".equals(mmdQuotation.getChannelNo()) || "2".equals(mmdQuotation.getChannelNo()))){
                if (zl.compareTo(new BigDecimal(10)) == -1){
                    zl = new BigDecimal(10);
                }
            }
            //如果是欧洲海运/空运，计费重不足12kg，按12kg算
            else if (europeCountryIdList.contains(order.getDestinationCountryId()) && ("1".equals(mmdQuotation.getChannelNo()) || "2".equals(mmdQuotation.getChannelNo()))){
                if (zl.compareTo(new BigDecimal(12)) == -1){
                    zl = new BigDecimal(12);
                }
            }
            volumeSum = volumeSum.add(zl);
        }
        //海卡类型的计费重 = max{整单的体积，整单的实重/300}
        if ("9".equals(mmdQuotation.getChannelNo())){
            weightSum = weightSum.divide(new BigDecimal(300), 2, RoundingMode.HALF_UP);
            BigDecimal chargeWeight = weightSum;
            if (volumeSum.compareTo(weightSum) == 1){
                chargeWeight = volumeSum;
            }
            logger.info("====volumeSum:{}, weightSum:{}, chargeWeight:{}",volumeSum,weightSum,chargeWeight.setScale(1, RoundingMode.UP));
            return chargeWeight.setScale(1, RoundingMode.UP);
        }
        return volumeSum.setScale(0, RoundingMode.UP);
    }

    public static void main(String[] args) {
        BigDecimal volumeSum = BigDecimal.ZERO;
        BigDecimal weightSum = BigDecimal.ZERO;
        for (int i = 0; i < 12; i++){
            MmdOrderDetail mmdOrderDetail = new MmdOrderDetail();
            mmdOrderDetail.setLength(new BigDecimal(61));
            mmdOrderDetail.setBreadth(new BigDecimal(60));
            mmdOrderDetail.setHeight(new BigDecimal(55));
            mmdOrderDetail.setWeight(new BigDecimal(10));

            weightSum = weightSum.add(mmdOrderDetail.getWeight());
            BigDecimal zl = (mmdOrderDetail.getLength().multiply(mmdOrderDetail.getBreadth()).multiply(mmdOrderDetail.getHeight())).divide(new BigDecimal(1000000), 3, RoundingMode.HALF_UP);
            volumeSum = volumeSum.add(zl);
        }
        weightSum = weightSum.divide(new BigDecimal(300), 2, RoundingMode.HALF_UP);
        BigDecimal chargeWeight = weightSum;
        if (volumeSum.compareTo(weightSum) == 1){
            chargeWeight = volumeSum;
        }
        System.out.println(chargeWeight.setScale(1, RoundingMode.UP));
    }

//    private static BigDecimal halfUp5(BigDecimal zl) {
//        String[] zls = zl.toString().split("\\.");
//        int zs = Integer.parseInt(zls[0]);
//        int xs = 0;
//        if (zls.length == 2){
//            xs = Integer.parseInt(zls[1]);
//        }
//        String xsStr = new String(xs+"");
//        String oneStr = xsStr.substring(0,1);
//        String twoStr = "0";
//        if (xsStr.length()==2){
//            twoStr = new String(xs+"").substring(1,2);
//        }
//        int one = Integer.parseInt(oneStr);
//        int two = Integer.parseInt(twoStr);
//
//        BigDecimal s = null;
//        if (xs > 0 && one < 5){
//            s = new BigDecimal(zs + 0.5);
//        }else if (one > 5 || (one == 5 && two > 0)){
//            s = new BigDecimal(zs + 1);
//        }else {
//            s = zl;
//        }
//        return s.setScale(2, RoundingMode.HALF_UP);
//    }

    private static BigDecimal halfUp5(BigDecimal zl) {
        String[] zls = zl.toString().split("\\.");
        int zs = Integer.parseInt(zls[0]);
        String xsStr = "0";
        if (zls.length == 2){
            xsStr = zls[1];
        }

        String firstXsStr = xsStr.substring(0,1);
        int firstXs = Integer.parseInt(firstXsStr);
        BigDecimal s = null;
        if (xsStr.length() == 1) {
            if (firstXs > 0 && firstXs < 5){
                s = new BigDecimal(zs + 0.5);
            }else if (firstXs > 5){
                s = new BigDecimal(zs + 1);
            }else {
                s = zl;
            }
        }else{
            String susXsStr = xsStr.substring(1, xsStr.length());
            int susXs = Integer.parseInt(susXsStr);
            if ((firstXs > 0 && firstXs < 5) || (firstXs == 0 && susXs > 0)){
                s = new BigDecimal(zs + 0.5);
            }else if (firstXs > 5 || (firstXs == 5 && susXs > 0)){
                s = new BigDecimal(zs + 1);
            }else {
                s = zl;
            }
        }
        return s.setScale(2, RoundingMode.HALF_UP);
    }

    /**
     * 计算当前子订单大的计费重量
     *
     * @return
     */
    private BigDecimal suCalculateChargedWeight(List<SuOrderDetail> allOrderProduct, MmdRoute mmdRoute) {
        //计算当前子订单大的计费重量
        BigDecimal weightSum = BigDecimal.ZERO;
        BigDecimal volumeSum = BigDecimal.ZERO;
        //订单总重量
        for (SuOrderDetail mmdOrderDetail : allOrderProduct) {
            weightSum = weightSum.add(mmdOrderDetail.getWeight());
            if (Objects.equals(5L, mmdRoute.getModeId()) || Objects.equals(6L, mmdRoute.getModeId())) {
                volumeSum = volumeSum.add((mmdOrderDetail.getLength().multiply(mmdOrderDetail.getBreadth()).multiply(mmdOrderDetail.getHeight())).divide(new BigDecimal(5000), 2, BigDecimal.ROUND_HALF_UP));
            } else {
                volumeSum = volumeSum.add((mmdOrderDetail.getLength().multiply(mmdOrderDetail.getBreadth()).multiply(mmdOrderDetail.getHeight())).divide(new BigDecimal(6000), 2, BigDecimal.ROUND_HALF_UP));
            }

            if (mmdRoute.getModeId() == 5 || mmdRoute.getModeId() == 6){
                volumeSum = halfUp5(volumeSum);
            }
        }
        //材积和重量哪个大，就以哪个为计算标准
        if (weightSum.compareTo(volumeSum) > 0) {
            return weightSum.setScale(0, RoundingMode.UP);
        }
        return volumeSum.setScale(0, RoundingMode.UP);
    }


    /**
     * 检验装箱单信息
     *
     * @param mmdOrderDetail
     */
    private void checkDetail(MmdOrderDetail mmdOrderDetail) {

        if (StringUtils.isBlank(mmdOrderDetail.getBoxNo())) {
            throw new GameException(new CODE(9999, "请填写FBA箱号"));
        }
        if (mmdOrderDetail.getWeight() == null) {
            throw new GameException(new CODE(9999, "请填写单件产品实重"));
        }
        if (mmdOrderDetail.getLength() == null || mmdOrderDetail.getBreadth() == null || mmdOrderDetail.getHeight() == null) {
            throw new GameException(new CODE(9999, "请准确填写长、宽、高"));
        }
    }


    /**
     * 检验装箱单信息
     *
     * @param mmdOrderDetail
     */
    private void checkProduct(MmdOrderProduct mmdOrderDetail) {

        if (StringUtils.isBlank(mmdOrderDetail.getProductEnName())) {
            throw new GameException(new CODE(9999, "请填写产品英文名称"));
        }
        if (StringUtils.isBlank(mmdOrderDetail.getProductCnName())) {
            throw new GameException(new CODE(9999, "请填写产品中文名称"));
        }
        if (StringUtils.isBlank(mmdOrderDetail.getHsCode())) {
            throw new GameException(new CODE(9999, "请填写HScode"));
        }
        if (mmdOrderDetail.getCount() == null) {
            throw new GameException(new CODE(9999, "请填写数量"));
        }
        if (mmdOrderDetail.getUnitPrice() == null) {
            throw new GameException(new CODE(9999, "请填写产品单价"));
        }
    }

    /**
     * 校验新增订单参数
     *
     * @param eo
     */
    private void checkParam(OrderEo eo) {
        if (eo.getDestinationCountryId() == null) {
            throw new GameException(new CODE(9999, "请选择目的国"));
        }
        if (StringUtils.isBlank(eo.getFlag())) {
            throw new GameException(new CODE(9999, "请选择保存草稿或提交订单"));
        }

        if (StringUtils.isBlank(eo.getIsvat())) {
            throw new GameException(new CODE(9999, "请选择是否是否包税"));
        }
        if (eo.getIsvat().equals("N")) {
            if (StringUtils.isBlank(eo.getIsuseVat())) {
                throw new GameException(new CODE(9999, "请选择是否使用自己VAT"));
            }
        }
        if (StringUtils.isBlank(eo.getRouteNo())) {
            throw new GameException(new CODE(9999, "请选择渠道路线"));
        }
        if (StringUtils.isBlank(eo.getIsAmazonFba())) {
            throw new GameException(new CODE(9999, "请选择是否是亚马逊FBA业务"));
        }

        if ("Y".equals(StringUtils.isBlank(eo.getIsAmazonFba())) && StringUtils.isBlank(eo.getFbaDepotName())) {
            throw new GameException(new CODE(9999, "请选择FBA仓库"));
        }

        if ("N".equals(StringUtils.isBlank(eo.getIsAmazonFba()))) {
            if (StringUtils.isBlank(eo.getFbaCity())) {
                throw new GameException(new CODE(9999, "请选择FBA仓库城市名称"));
            }
            if (StringUtils.isBlank(eo.getFbaPostcode())) {
                throw new GameException(new CODE(9999, "请选择FBA仓库邮编"));
            }
            if (StringUtils.isBlank(eo.getFbaLinkman())) {
                throw new GameException(new CODE(9999, "请选择FBA仓库联系人"));
            }
            if (StringUtils.isBlank(eo.getFbaTel())) {
                throw new GameException(new CODE(9999, "请选择FBA仓库联系方式"));
            }
            if (StringUtils.isBlank(eo.getFbaAddress())) {
                throw new GameException(new CODE(9999, "请选择FBA仓库地址"));
            }
        }
        //配置装箱单
        if (StringUtils.isBlank(eo.getBoxDetails())) {
            throw new GameException(new CODE(9999, "请填写装箱单"));
        }
    }

    @Override
    public MyOrderBaseVo myOrderList(MyOrderQueryEo eo) {
        logger.info("######查询参数#####{}", JSON.toJSONString(eo));
        MmdUser mmdUser = userDao.selectByPrimaryKey(eo.getUid());
        if (mmdUser == null) {
            throw new GameException(new CODE(9999, "请登录"));
        }
        if (eo.getStartOrderTime() != null && eo.getEndOrderTime() != null && eo.getStartOrderTime().after(eo.getEndOrderTime())) {
            throw new GameException(new CODE(9999, "请选择正确的时间段"));
        }
        MyOrderBaseVo baseVo = new MyOrderBaseVo();

        baseVo.setUserName(mmdUser.getUserName());
        List<MmdOrder> list = mmdOrderDao.myOrderList(eo);
        List<MyOrderQueryVo> vos = new ArrayList<>();
        MyOrderQueryVo vo = null;
        for (MmdOrder order : list) {
            //组装单个订单数据
            vo = new MyOrderQueryVo();
            BeanUtils.copyProperties(order, vo);
            vo.setStatusDesc(StatusEnums.getStatusEnum(order.getStatus()).getName());
            //计费单价
            vo.setUnitPrice(order.getChargedPrice());
            //订单总重量
            vo.setWeightSum(order.getChargedWeight());
            if (StringUtils.isBlank(order.getIscog())) {
                //非单独清关，需要把中港费、单独报关费返回0
                vo.setSingleDeclareFee(BigDecimal.ZERO);
                vo.setZgFee(BigDecimal.ZERO);
            }
            vos.add(vo);
        }

        //未付款的订单金额
        baseVo.setNoPayAmount(BigDecimal.ZERO);
        MmdBillRecord record = mmdBillRecordDao.selectMaxBill(eo.getUid());
        if (record != null && record.getTotalAmount().compareTo(BigDecimal.ZERO) < 0) {
            baseVo.setNoPayAmount(record.getTotalAmount().negate());
        }
        baseVo.setVos(vos);

        return baseVo;
    }

    /**
     * 获取当前报价单对应的最大附加费
     *
     * @param quotationNo
     * @return
     */
    private BigDecimal calculateAttachFee(String quotationNo, List<MmdOrderProduct> mmdOrderDetails) {
        //根据订单的hscode去找到报价单对应的hscode

        List<String> hscodes = mmdOrderDetails.stream().map(MmdOrderProduct::getHsCode).collect(Collectors.toList());
        List<MmdQuotationHscode> mmdQuotationHscodes = mmdQuotationHscodeDao.selectListByHsCode(quotationNo, hscodes);

        if (!CollectionUtils.isEmpty(mmdQuotationHscodes)) {
            if (mmdQuotationHscodes.size() == 1) {
                return mmdQuotationHscodes.get(0).getAttachFee();
            }
            Optional<MmdQuotationHscode> first = mmdQuotationHscodes.stream().sorted(Comparator.comparing(MmdQuotationHscode::getAttachFee).reversed()).findFirst();
            if (first.isPresent()) {
                return first.get().getAttachFee();
            }
        }
        return BigDecimal.ZERO;
    }


    /**
     * 计算订单的单价
     *
     * @param order
     * @return
     */
    private BigDecimal calculateUnitPrice(BigDecimal chargedWeight, MmdOrder order, MmdQuotation mmdQuotation) {
        logger.info("#####计费单价计算开始，orderNo:{}#####",order.getOrderNo());
        BigDecimal result = BigDecimal.ZERO;

        logger.info("#####参与计费单价的重量={}#####", chargedWeight);
        //这个List元素顺序不能变
        List<BigDecimal> kgList = otherKgList;
        if (mmdQuotation.getChannelNo().equals("1")){
            kgList = haiYunKgList;
        }else if (mmdQuotation.getChannelNo().equals("5")){
            kgList = upsRedKgList;
        }
        BigDecimal temp = BigDecimal.ZERO;
        for (int i = 0; i < kgList.size(); i++) {
            if (chargedWeight.compareTo(kgList.get(i)) <= 0) {
                if (i == 0 || (chargedWeight.compareTo(kgList.get(i)) == 0)) {
                    temp = kgList.get(i);
                } else {
                    temp = kgList.get(i - 1);
                }
                break;
            } else {
                //当计费重量大于1001KG就取1001KG
                if (kgList.get(i).compareTo(new BigDecimal(1001)) == 0) {
                    temp = kgList.get(i);
                }
            }

        }
        String kg = "kg" + temp;
        MmdQuotationDetail detail = new MmdQuotationDetail();
        detail.setQuotationNo(mmdQuotation.getQuotationNo());
        detail.setSonAreaId(order.getDestinationCountryId());
        List<MmdQuotationDetail> mmdQuotationDetails = mmdQuotationDetailDao.selectByKeySelective(detail);
        logger.info("mmdQuotationDetails.size=={}, detail:{}", mmdQuotationDetails.size(), JSONObject.toJSONString(detail));
        if (!CollectionUtils.isEmpty(mmdQuotationDetails)) {
            MmdQuotationDetail mmdQuotationDetail = mmdQuotationDetails.get(0);
            Map<String, BigDecimal> hashmap = new HashMap<>();
            hashmap.put("kg21", mmdQuotationDetail.getKg21());
            hashmap.put("kg23", mmdQuotationDetail.getKg23());
            hashmap.put("kg46", mmdQuotationDetail.getKg46());
            hashmap.put("kg71", mmdQuotationDetail.getKg71());
            hashmap.put("kg100", mmdQuotationDetail.getKg100());
            hashmap.put("kg101", mmdQuotationDetail.getKg101());
            hashmap.put("kg301", mmdQuotationDetail.getKg301());
            hashmap.put("kg501", mmdQuotationDetail.getKg501());
            hashmap.put("kg1001", mmdQuotationDetail.getKg1001());
            logger.info("#####1计费单价计算结束，计费单价={}, kg:{}#####", hashmap.get(kg), kg);
            return hashmap.get(kg);
        }
        logger.info("#####2计费单价计算结束，计费单价={}#####", result);
        return result;
    }

    /**
     * 计算订单的历史单价
     *
     * @param order
     * @return
     */
    private BigDecimal calculateHistoryUnitPrice(BigDecimal chargedWeight, MmdOrder order, MmdQuotationHistory mmdQuotation) {
        logger.info("#####计费历史单价计算开始，orderNo:{}#####",order.getOrderNo());
        BigDecimal result = BigDecimal.ZERO;

        logger.info("#####参与计费历史单价的重量={}#####", chargedWeight);
        //这个List元素顺序不能变
        List<BigDecimal> kgList = otherKgList;
        if (mmdQuotation.getChannelNo().equals("1")){
            kgList = haiYunKgList;
        }else if (mmdQuotation.getChannelNo().equals("5")){
            kgList = upsRedKgList;
        }
        BigDecimal temp = BigDecimal.ZERO;
        for (int i = 0; i < kgList.size(); i++) {
            if (chargedWeight.compareTo(kgList.get(i)) <= 0) {
                if (i == 0 || (chargedWeight.compareTo(kgList.get(i)) == 0)) {
                    temp = kgList.get(i);
                } else {
                    temp = kgList.get(i - 1);
                }
                break;
            } else {
                //当计费重量大于1001KG就取1001KG
                if (kgList.get(i).compareTo(new BigDecimal(1001)) == 0) {
                    temp = kgList.get(i);
                }
            }

        }
        String kg = "kg" + temp;
        MmdQuotationDetailHistory detail = new MmdQuotationDetailHistory();
        detail.setHistoryId(mmdQuotation.getHistoryId());
        detail.setSonAreaId(order.getDestinationCountryId());
        List<MmdQuotationDetailHistory> mmdQuotationDetails = mmdQuotationDetailHistoryMapper.selectByKeySelective(detail);
        logger.info("mmdQuotationDetails.size=={}, detail:{}", mmdQuotationDetails.size(), JSONObject.toJSONString(detail));
        if (!CollectionUtils.isEmpty(mmdQuotationDetails)) {
            MmdQuotationDetailHistory mmdQuotationDetail = mmdQuotationDetails.get(0);
            Map<String, BigDecimal> hashmap = new HashMap<>();
            hashmap.put("kg21", mmdQuotationDetail.getKg21());
            hashmap.put("kg23", mmdQuotationDetail.getKg23());
            hashmap.put("kg46", mmdQuotationDetail.getKg46());
            hashmap.put("kg71", mmdQuotationDetail.getKg71());
            hashmap.put("kg100", mmdQuotationDetail.getKg100());
            hashmap.put("kg101", mmdQuotationDetail.getKg101());
            hashmap.put("kg301", mmdQuotationDetail.getKg301());
            hashmap.put("kg501", mmdQuotationDetail.getKg501());
            hashmap.put("kg1001", mmdQuotationDetail.getKg1001());
            logger.info("#####1计费历史单价计算结束，计费单价={}, kg:{}#####", hashmap.get(kg), kg);
            return hashmap.get(kg);
        }
        logger.info("#####2计费历史单价计算结束，计费单价={}#####", result);
        return result;

    }

    /**
     * 计算订单的单价
     *
     * @param order
     * @return
     */
    private BigDecimal calculateCbmUnitPrice(BigDecimal chargedWeight, MmdOrder order, MmdQuotation mmdQuotation) {
        logger.info("#####计费cbm单价计算开始#####");
        BigDecimal result = BigDecimal.ZERO;

        logger.info("#####参与cbm计费单价的重量={}#####", chargedWeight);
        //这个List元素顺序不能变
        List<BigDecimal> kgList = Arrays.asList(
                new BigDecimal(1),
                new BigDecimal(2),
                new BigDecimal(5),
                new BigDecimal(10));
        BigDecimal temp = BigDecimal.ZERO;
        for (int i = 0; i < kgList.size(); i++) {
            if (chargedWeight.compareTo(kgList.get(i)) <= 0) {
                if (i == 0 || (chargedWeight.compareTo(kgList.get(i)) == 0)) {
                    temp = kgList.get(i);
                } else {
                    temp = kgList.get(i - 1);
                }
                break;
            } else {
                //当计费重量大于1001KG就取1001KG
                if (kgList.get(i).compareTo(new BigDecimal(10)) == 0) {
                    temp = kgList.get(i);
                }
            }

        }
        String kg = "cbm" + temp;
        MmdQuotationDetail detail = new MmdQuotationDetail();
        detail.setQuotationNo(mmdQuotation.getQuotationNo());
        detail.setSonAreaId(order.getDestinationCountryId());
        List<MmdQuotationDetail> mmdQuotationDetails = mmdQuotationDetailDao.selectByKeySelective(detail);
        logger.info("mmdQuotationDetails.size=={}, detail:{}", mmdQuotationDetails.size(), JSONObject.toJSONString(detail));
        if (!CollectionUtils.isEmpty(mmdQuotationDetails)) {
            MmdQuotationDetail mmdQuotationDetail = mmdQuotationDetails.get(0);
            Map<String, BigDecimal> hashmap = new HashMap<>();
            hashmap.put("cbm1", mmdQuotationDetail.getCbm1());
            hashmap.put("cbm2", mmdQuotationDetail.getCbm2());
            hashmap.put("cbm5", mmdQuotationDetail.getCbm5());
            hashmap.put("cbm10", mmdQuotationDetail.getCbm10());
            logger.info("#####1计费cbm单价计算结束，计费单价={}, cbm:{}#####", hashmap.get(kg), kg);
            return hashmap.get(kg);
        }
        logger.info("#####2计费cbm单价计算结束，计费单价={}#####", result);
        return result;
    }

    /**
     * 计算订单的单价
     *
     * @param order
     * @return
     */
    private BigDecimal calculateCbmHistoryUnitPrice(BigDecimal chargedWeight, MmdOrder order, MmdQuotationHistory mmdQuotation) {
        logger.info("#####计费cbm历史单价计算开始#####");
        BigDecimal result = BigDecimal.ZERO;

        logger.info("#####参与cbm计费历史单价的重量={}#####", chargedWeight);
        //这个List元素顺序不能变
        List<BigDecimal> kgList = Arrays.asList(
                new BigDecimal(1),
                new BigDecimal(2),
                new BigDecimal(5),
                new BigDecimal(10));
        BigDecimal temp = BigDecimal.ZERO;
        for (int i = 0; i < kgList.size(); i++) {
            if (chargedWeight.compareTo(kgList.get(i)) <= 0) {
                if (i == 0 || (chargedWeight.compareTo(kgList.get(i)) == 0)) {
                    temp = kgList.get(i);
                } else {
                    temp = kgList.get(i - 1);
                }
                break;
            } else {
                //当计费重量大于1001KG就取1001KG
                if (kgList.get(i).compareTo(new BigDecimal(10)) == 0) {
                    temp = kgList.get(i);
                }
            }

        }
        String kg = "cbm" + temp;
        MmdQuotationDetailHistory detail = new MmdQuotationDetailHistory();
        detail.setHistoryId(mmdQuotation.getHistoryId());
        detail.setSonAreaId(order.getDestinationCountryId());
        List<MmdQuotationDetailHistory> mmdQuotationDetails = mmdQuotationDetailHistoryMapper.selectByKeySelective(detail);
        logger.info("mmdQuotationDetails.size=={}, detail:{}", mmdQuotationDetails.size(), JSONObject.toJSONString(detail));
        if (!CollectionUtils.isEmpty(mmdQuotationDetails)) {
            MmdQuotationDetailHistory mmdQuotationDetail = mmdQuotationDetails.get(0);
            Map<String, BigDecimal> hashmap = new HashMap<>();
            hashmap.put("cbm1", mmdQuotationDetail.getCbm1());
            hashmap.put("cbm2", mmdQuotationDetail.getCbm2());
            hashmap.put("cbm5", mmdQuotationDetail.getCbm5());
            hashmap.put("cbm10", mmdQuotationDetail.getCbm10());
            logger.info("#####1计费cbm历史单价计算结束，计费单价={}, cbm:{}#####", hashmap.get(kg), kg);
            return hashmap.get(kg);
        }
        logger.info("#####2计费cbm历史单价计算结束，计费单价={}#####", result);
        return result;

    }

    /**
     * 计算订单的单价
     *
     * @param order
     * @return
     */
    private BigDecimal suCalculateUnitPrice(BigDecimal chargedWeight, SuOrder order, MmdRoute mmdRoute) {
        logger.info("#####计费单价计算开始#####");
        BigDecimal result = BigDecimal.ZERO;

        logger.info("#####参与计费单价的重量={}#####", chargedWeight);
        //这个List元素顺序不能变
        List<BigDecimal> kgList = Arrays.asList(
                new BigDecimal(21),
                new BigDecimal(46),
                new BigDecimal(71),
                new BigDecimal(101),
                new BigDecimal(301),
                new BigDecimal(501),
                new BigDecimal(1001));
        BigDecimal temp = BigDecimal.ZERO;
        for (int i = 0; i < kgList.size(); i++) {
//            if (chargedWeight.compareTo(kgList.get(i)) <= 0) {
//                if (i == 0) {
//                    temp = kgList.get(i);
//                } else {
//                    temp = kgList.get(i - 1);
//                }
//                break;
//            } else {
//                //当计费重量大于1001KG就取1001KG
//                if (kgList.get(i).compareTo(new BigDecimal(1001)) == 0) {
//                    temp = kgList.get(i);
//                }
//            }

            if (chargedWeight.compareTo(kgList.get(i)) <= 0) {
                if (i == 0 || (chargedWeight.compareTo(kgList.get(i)) == 0)) {
                    temp = kgList.get(i);
                } else {
                    temp = kgList.get(i - 1);
                }
                break;
            } else {
                //当计费重量大于1001KG就取1001KG
                if (kgList.get(i).compareTo(new BigDecimal(1001)) == 0) {
                    temp = kgList.get(i);
                }
            }
        }
        String kg = "kg" + temp;
        MmdRouteDetail detail = new MmdRouteDetail();
        detail.setRouteNo(mmdRoute.getRouteNo());
        detail.setSonAreaId(order.getDestinationCountryId());
        List<MmdRouteDetail> mmdQuotationDetails = routeDetailDao.selectByKeySelective(detail);
        if (!CollectionUtils.isEmpty(mmdQuotationDetails)) {
            MmdRouteDetail mmdRouteDetail = mmdQuotationDetails.get(0);
            Map<String, BigDecimal> hashmap = new HashMap<>();
            hashmap.put("kg21", mmdRouteDetail.getKg21());
            hashmap.put("kg46", mmdRouteDetail.getKg46());
            hashmap.put("kg71", mmdRouteDetail.getKg71());
            hashmap.put("kg101", mmdRouteDetail.getKg101());
            hashmap.put("kg301", mmdRouteDetail.getKg301());
            hashmap.put("kg501", mmdRouteDetail.getKg501());
            hashmap.put("kg1001", mmdRouteDetail.getKg1001());
            logger.info("#####1计费单价计算结束，计费单价={}, kg:{}#####", hashmap.get(kg), kg);
            return hashmap.get(kg);
        }
        logger.info("2#####计费单价计算结束，计费单价={}#####", result);
        return result;

    }


    /**
     * 获取供应商路线对应的最大附加费
     *
     * @return
     */
    private BigDecimal calculateSuAttachFee(MmdRoute mmdRoute, List<MmdOrderProduct> productList) {
        //根据订单的hscode去找到报价单对应的hscode
        List<String> hscodes = productList.stream().map(MmdOrderProduct::getHsCode).collect(Collectors.toList());
        List<MmdRouteHscode> mmdQuotationHscodes = routeHscodeDao.selectListByHsCode(mmdRoute.getRouteNo(), hscodes);

        if (!CollectionUtils.isEmpty(mmdQuotationHscodes)) {
            if (mmdQuotationHscodes.size() == 1) {
                return mmdQuotationHscodes.get(0).getAttachFee();
            }
            Optional<MmdRouteHscode> first = mmdQuotationHscodes.stream().max(Comparator.comparing(MmdRouteHscode::getAttachFee));
            if (first.isPresent()) {
                return first.get().getAttachFee();
            }
        }
        return BigDecimal.ZERO;
    }

    /**
     * 计算供应商订单的单价
     *
     * @return
     */
    private BigDecimal calculateSuUnitPrice(BigDecimal chargedWeight, MmdRoute mmdRoute, Long destinationCountryId) {
        logger.info("#####计费单价计算开始#####");
        BigDecimal result = BigDecimal.ZERO;

        logger.info("#####参与计费单价的重量={}#####", chargedWeight);
        //这个List元素顺序不能变
        List<BigDecimal> kgList = Arrays.asList(
                new BigDecimal(21),
                new BigDecimal(46),
                new BigDecimal(71),
                new BigDecimal(101),
                new BigDecimal(301),
                new BigDecimal(501),
                new BigDecimal(1001));
        BigDecimal temp = BigDecimal.ZERO;
        for (int i = 0; i < kgList.size(); i++) {
            if (chargedWeight.compareTo(kgList.get(i)) <= 0) {
                if (i == 0) {
                    temp = kgList.get(i);
                } else {
                    temp = kgList.get(i - 1);
                }
                break;
            } else {
                //当计费重量大于1001KG就取1001KG
                if (kgList.get(i).compareTo(new BigDecimal(1001)) == 0) {
                    temp = kgList.get(i);
                }
            }

        }
        String kg = "kg" + temp;

        List<MmdRouteDetail> routeDetailList = routeDetailDao.getRouteDetail(mmdRoute.getRouteNo());
        MmdRouteDetail routeDetail = routeDetailList.stream().filter(route -> Objects.equals(route.getSonAreaId(), destinationCountryId)).findFirst().orElse(null);
        if (routeDetail != null) {
            Map<String, BigDecimal> hashmap = new HashMap<>();
            hashmap.put("kg21", routeDetail.getKg21());
            hashmap.put("kg46", routeDetail.getKg46());
            hashmap.put("kg71", routeDetail.getKg71());
            hashmap.put("kg101", routeDetail.getKg101());
            hashmap.put("kg301", routeDetail.getKg301());
            hashmap.put("kg501", routeDetail.getKg501());
            hashmap.put("kg1001", routeDetail.getKg1001());
            logger.info("#####计费单价计算结束，计费单价={}#####", hashmap.get(kg));
            return hashmap.get(kg);
        }
        logger.info("#####计费单价计算结束，计费单价={}#####", result);
        return result;

    }

    @Override
    public PageData<MyOrderQueryVo> orderList(MyOrderQueryEo eo) {
        logger.info("######查询参数#####{}", JSON.toJSONString(eo));
        MmdUser mmdUser = userDao.selectByPrimaryKey(eo.getUid());
        if (mmdUser == null) {
            throw new GameException(new CODE(9999, "请登录"));
        }
        List<MyOrderQueryVo> vos = new ArrayList<>();
        if (!mmdUser.getLevel().equals("admin")) {
            throw new GameException(new CODE(9999, "请选择使用管理员账号登录"));
        }
        if (eo.getStartOrderTime() != null && eo.getEndOrderTime() != null && eo.getStartOrderTime().after(eo.getEndOrderTime())) {
            throw new GameException(new CODE(9999, "请选择正确的时间段"));
        }
        eo.setStartLimit((eo.getCurPage() - 1) * eo.getPageSize());
        List<MmdOrder> orders = mmdOrderDao.orderList(eo);
        MyOrderQueryVo vo = null;
        OrderListGoodsDetailVo goodsDetail = null;
        Map<String, BigDecimal> hscodeMapResult = new HashMap<>();
        for (MmdOrder order : orders) {
            //组装单个订单数据
            MmdQuotation mmdQuotation = mmdQuotationDao.selectQuotationByRouteNo(order.getRouteNo());
            logger.info("orderList   routeNo:{}, mmdQuotation:{}",order.getRouteNo(),mmdQuotation==null?null:"不为空");
            if (mmdQuotation != null) {
                List<MmdQuotationHscode> mmdQuotationHscodes = mmdQuotationHscodeDao.selectListByHsCode(mmdQuotation.getQuotationNo(), new ArrayList<>());
                if (!CollectionUtils.isEmpty(mmdQuotationHscodes)) {
                    Map<String, BigDecimal> hscodeMap = mmdQuotationHscodes.stream().collect(Collectors.toMap(MmdQuotationHscode::getHscode, MmdQuotationHscode::getAttachFee));
                    if (!hscodeMap.isEmpty()) {
                        hscodeMapResult.putAll(hscodeMap);
                    }
                }
            }

            String level = AdminInterceptor.getUserLoginContext().getLevel();

            vo = new MyOrderQueryVo();
            MmdUser user = userDao.selectByPrimaryKey(order.getUid());
            BeanUtils.copyProperties(order, vo);
            if (user != null) {
                vo.setUserName(user.getUserName());
                vo.setAccount(user.getAccount());
            }
            //获取渠道路线费用
            vo.setStatusDesc(StatusEnums.getStatusEnum(order.getStatus()).getName());
            //计费单价
            vo.setUnitPrice(order.getChargedPrice());
            //订单总重量
            vo.setWeightSum(order.getChargedWeight());
            vo.setChargeWeight(order.getChargedWeight());
            if (StringUtils.isBlank(order.getIscog())) {
                //非单独清关，需要把中港费、单独报关费返回0
                vo.setSingleDeclareFee(BigDecimal.ZERO);
                vo.setZgFee(BigDecimal.ZERO);
            }
            List<MmdOrderDetailVo> list1 = mmdOrderDetailDao.list(order.getOrderNo());
            vo.setPkgNumber(list1.size());
            List<OrderListGoodsDetailVo> goodsDetails = new ArrayList<>();
            for (MmdOrderDetailVo mmdOrderDetailVo : list1) {
                List<MmdOrderProduct> list2 = mmdOrderProductDao.list(mmdOrderDetailVo.getPkgNo(), level);
                for (MmdOrderProduct mmdOrderProduct : list2) {
                    goodsDetail = new OrderListGoodsDetailVo();
                    goodsDetail.setPid(mmdOrderProduct.getPid());
                    goodsDetail.setPkgNo(mmdOrderProduct.getPkgNo());
                    goodsDetail.setBoxNo(mmdOrderProduct.getBoxNo());
                    goodsDetail.setHsCode(mmdOrderProduct.getHsCode());
                    goodsDetail.setIsem(mmdOrderProduct.getIsem());
                    goodsDetail.setProductCnName(mmdOrderProduct.getProductCnName());
                    BigDecimal volume = BigDecimal.ZERO;
                    if (mmdQuotation != null) {
                        if ("5".equals(mmdQuotation.getChannelNo()) || "6".equals(mmdQuotation.getChannelNo())) {
                            volume = (mmdOrderDetailVo.getLength().multiply(mmdOrderDetailVo.getBreadth()).multiply(mmdOrderDetailVo.getHeight())).divide(new BigDecimal(5000), 0, BigDecimal.ROUND_UP);
                        } else {
                            volume = (mmdOrderDetailVo.getLength().multiply(mmdOrderDetailVo.getBreadth()).multiply(mmdOrderDetailVo.getHeight())).divide(new BigDecimal(6000), 0, BigDecimal.ROUND_UP);
                        }
                    }
                    goodsDetail.setVolume(volume);
                    goodsDetail.setAttachFee(hscodeMapResult.getOrDefault(mmdOrderProduct.getHsCode(), BigDecimal.ZERO));
                    goodsDetail.setLength(mmdOrderDetailVo.getLength());
                    goodsDetail.setWeight(mmdOrderDetailVo.getWeight());
                    goodsDetail.setBreadth(mmdOrderDetailVo.getBreadth());
                    goodsDetail.setHeight(mmdOrderDetailVo.getHeight());
                    goodsDetails.add(goodsDetail);
                }
            }
            vo.setGoodsDetailList(goodsDetails);
            vos.add(vo);
        }
        PageInfo<MyOrderQueryVo> result = new PageInfo<>(vos);
        Integer count = mmdOrderDao.countOrderList(eo);
        result.setTotal(count);
        PageData<MyOrderQueryVo> data = new PageData<>(result);
        data.setCurPage(eo.getCurPage());
        data.setPageSize(eo.getPageSize());
        return data;
    }

    @Override
    @Transactional
    public void batchDeleteOrder(List<String> orderNoList) {
        for (String orderNo : orderNoList){
            MmdOrder order = mmdOrderDao.selectByPrimaryKey(orderNo);
            MmdOrder updateOrder = new MmdOrder();
            updateOrder.setOrderNo(orderNo);
            updateOrder.setIsDelete(1);
            mmdOrderDao.updateByPrimaryKeySelective(updateOrder);

            //财务做对冲
            BigDecimal amount = Optional.ofNullable(mmdBillRecordDao.collectAmountByOrder(orderNo)).orElse(BigDecimal.ZERO);

            //对冲账单
            MmdBillRecord record = new MmdBillRecord();
            record.setBusinessNo(orderNo);
            record.setCreateTime(new Date());
            record.setUserType(UserTypeEnums.USER.getCode());
            record.setUid(order.getUid());
            record.setAmcount(amount.negate());
            record.setTotalAmount(amount);
            record.setType(BillTypeEnums.ORDER.getCode());
            MmdBillRecord maxRecord = mmdBillRecordDao.selectMaxBill(order.getUid());
            if (maxRecord != null) {
                record.setTotalAmount(maxRecord.getTotalAmount().add(amount));
            }
            record.setRemark("对冲：订单" + order.getOrderNo() + "，供应商删除订单。");
            mmdBillRecordDao.insert(record);
        }
    }

    @Override
    public boolean backLogistics(BackLogisticsEo eo) {
        MmdOrder order = mmdOrderDao.selectByPrimaryKey(eo.getOrderNo());
        if (order == null) {
            throw new GameException(new CODE(9999, "订单不存在"));
        }
        if (!order.getStatus().equals(StatusEnums.WAREHOUSING.getCode()) && !order.getStatus().equals(StatusEnums.DELIVERED.getCode())) {
            throw new GameException(new CODE(9999, "订单还未入仓，无法回传物流单号"));
        }
        MmdOrder order1 = new MmdOrder();
        order1.setOrderNo(eo.getOrderNo());
        order1.setLogisticsCompanyCode(eo.getLogisticsCompanyCode());
        order1.setLogisticsCompanyName(eo.getLogisticsCompanyName());
        order1.setLogisticsNo(eo.getLogisticsNo());
        order1.setStatus(StatusEnums.DELIVERED.getCode());
        return mmdOrderDao.updateByPrimaryKeySelective(order1) == 1;
    }

    @Override
    @Transactional
    public boolean backBox(OrderBoxDetailVo vo) {
        MmdOrder order = mmdOrderDao.selectByPrimaryKey(vo.getOrderNo());
        if (order == null) {
            throw new GameException(new CODE(9999, "订单不存在"));
        }
        //只要是审核的订单，可以回传多次箱单
        if (order.getStatus() < 3) {
            throw new GameException(new CODE(9999, "订单还未审核，无法进行箱单确认"));
        }
        MmdOrder order1 = new MmdOrder();
        order1.setIscog(order.getIscog());
        order1.setOrderNo(vo.getOrderNo());
        order1.setStatus(StatusEnums.WAREHOUSING.getCode());
        order1.setBackBoxRemark(vo.getBackBoxRemark());

        //更新box
        List<OrderBoxItemVo> itemVos = JSON.parseArray(vo.getItemStr(), OrderBoxItemVo.class);

        List<MmdOrderDetailEo> mmdOrderDetails = new ArrayList<>();
        BigDecimal chargeWeight = BigDecimal.ZERO;
        for (OrderBoxItemVo itemVo : itemVos) {
            MmdOrderDetailEo detail = new MmdOrderDetailEo();
            detail.setPkgNo(itemVo.getPkgNo());
            detail.setLength(itemVo.getLength());
            detail.setBreadth(itemVo.getBreadth());
            detail.setHeight(itemVo.getHeight());
            detail.setWeight(itemVo.getWeight());
            mmdOrderDetails.add(detail);

            chargeWeight = chargeWeight.add(itemVo.getJfz());
        }
        //设置修改的费用
        order1.setAttachFee(vo.getAttachFee()==null?BigDecimal.ZERO:vo.getAttachFee());
        order1.setZgFee(vo.getZgFee());
        order1.setSingleOperatFee(vo.getSingleOperatFee());
        order1.setSingleDeclareFee(vo.getSingleDeclareFee());

        //材积、重量变化，需要重新计算计费单价、计费重量、总价
        MmdQuotation mmdQuotation = mmdQuotationDao.selectQuotationByRouteNo(order.getRouteNo());
        if (mmdQuotation == null){
            throw new GameException(new CODE(9999, "没有匹配的报价单"));
        }
        //计费重量
        if ("1".equals(mmdQuotation.getChannelNo()) && chargeWeight.compareTo(new BigDecimal(100)) == -1){
            //如果是海派，整单不足100KG按100KG算
            chargeWeight = new BigDecimal(100);
        }else if ("5".equals(mmdQuotation.getChannelNo()) && chargeWeight.compareTo(new BigDecimal(23)) == -1){
            //如果是UPS红单，整单不足23KG按23KG算
            chargeWeight = new BigDecimal(23);
        }

        order1.setChargedWeight(chargeWeight.setScale(0, RoundingMode.UP));
        order.setChargedWeight(order1.getChargedWeight());

        //计费单价
        if (order.getQuotationHistoryId() != null) {
            MmdQuotationHistory mmdQuotationHistory = mmdQuotationHistoryMapper.selectByPrimaryKey(order.getQuotationHistoryId());
            if (!"9".equals(mmdQuotation.getChannelNo())) {
                order.setChargedPrice(this.calculateHistoryUnitPrice(order.getChargedWeight(), order, mmdQuotationHistory));
            } else {
                order.setChargedPrice(this.calculateCbmHistoryUnitPrice(order.getChargedWeight(), order, mmdQuotationHistory));
            }

        }else{
            order1.setChargedPrice(order.getChargedPrice());
            //计算订单的总价
            order.setChargedPrice(order1.getChargedPrice()==null?BigDecimal.ZERO:order1.getChargedPrice());
        }
        //计算订单的总价
        order1.setChargedPrice(order.getChargedPrice());
        order.setAttachFee(order1.getAttachFee());
        order1.setTotalFee(this.calculateTotalFee(order, mmdQuotation));

        mmdOrderDetails.forEach(detail -> mmdOrderDetailDao.updateByPrimaryKeySelective(detail));

        MmdBillRecord oldRecord = mmdBillRecordDao.selectByOrder(order1.getOrderNo());
        MmdBillRecord hedgeRecord = null;
        if (oldRecord != null) {
            //对冲账单
            hedgeRecord = new MmdBillRecord();
            hedgeRecord.setBusinessNo(order.getOrderNo());
            hedgeRecord.setCreateTime(new Date());
            hedgeRecord.setUserType(UserTypeEnums.USER.getCode());
            hedgeRecord.setUid(order.getUid());
            hedgeRecord.setAmcount(oldRecord.getAmcount().negate());
            hedgeRecord.setTotalAmount(oldRecord.getAmcount());
            hedgeRecord.setType(BillTypeEnums.ORDER.getCode());
            MmdBillRecord maxRecord = mmdBillRecordDao.selectMaxBill(order.getUid());
            if (maxRecord != null) {
                hedgeRecord.setTotalAmount(maxRecord.getTotalAmount().subtract(hedgeRecord.getAmcount()));
            }
            hedgeRecord.setRemark("对冲：订单" + order.getOrderNo() + "，供应商修改订单信息，记录作废。");
            mmdBillRecordDao.insert(hedgeRecord);
        }

        //保存账单的账单
        MmdBillRecord record = new MmdBillRecord();
        record.setBusinessNo(order.getOrderNo());
        record.setCreateTime(new Date());
        record.setUserType(UserTypeEnums.USER.getCode());
        record.setUid(order.getUid());
        record.setAmcount(order1.getTotalFee());
        record.setTotalAmount(order1.getTotalFee().negate());
        record.setType(BillTypeEnums.ORDER.getCode());
        MmdBillRecord maxRecord = mmdBillRecordDao.selectMaxBill(order.getUid());
        if (maxRecord != null) {
            record.setTotalAmount(maxRecord.getTotalAmount().add(order1.getTotalFee().negate()));
        }
        record.setRemark("订单" + order.getOrderNo() + ",供应商已确认箱单。");
        mmdBillRecordDao.insert(record);

        return mmdOrderDao.updateByPrimaryKeySelective(order1) == 1;
    }

    @Override
    @Transactional
    public boolean backSuBox(SuOrderBoxDetailVo vo) {
        SuOrder order = suOrderDao.selectByPrimaryKey(vo.getBatchNo());
        if (order == null) {
            throw new GameException(new CODE(9999, "主订单不存在"));
        }
        //更新box
        List<OrderBoxItemVo> itemVos = JSON.parseArray(vo.getItemStr(), OrderBoxItemVo.class);

        List<SuOrderDetail> mmdOrderDetails = new ArrayList<>();
        MmdRoute mmdRoute = mmdRouteDao.selectByPrimaryKey(order.getRouteNo());
        BigDecimal weightSum = BigDecimal.ZERO;
        BigDecimal volumeSum = BigDecimal.ZERO;
        BigDecimal jfzTotal = BigDecimal.ZERO;
        for (OrderBoxItemVo itemVo : itemVos) {
            SuOrderDetail detail = new SuOrderDetail();
            detail.setPkgNo(itemVo.getPkgNo());
            detail.setLength(itemVo.getLength());
            detail.setBreadth(itemVo.getBreadth());
            detail.setHeight(itemVo.getHeight());
            detail.setWeight(itemVo.getWeight());
            mmdOrderDetails.add(detail);

            BigDecimal volume = BigDecimal.ZERO;
            if (mmdRoute.getModeId() == 5 || mmdRoute.getModeId() == 6) {
                volume = (detail.getLength().multiply(detail.getBreadth()).multiply(detail.getHeight())).divide(new BigDecimal(5000), 2, RoundingMode.HALF_UP);
            } else if (mmdRoute.getModeId() == 9) {
                volume = (detail.getLength().multiply(detail.getBreadth()).multiply(detail.getHeight())).divide(new BigDecimal(1000000), 3, RoundingMode.HALF_UP);
            }else{
                volume = (detail.getLength().multiply(detail.getBreadth()).multiply(detail.getHeight())).divide(new BigDecimal(6000), 2, RoundingMode.HALF_UP);
            }

            BigDecimal jfz = (itemVo.getWeight()==null?BigDecimal.ZERO:itemVo.getWeight()).compareTo(volume==null?BigDecimal.ZERO:volume) == 1 ? itemVo.getWeight() : volume;
            //UPS的计费重要进半位
            if (mmdRoute.getModeId() == 5 || mmdRoute.getModeId() == 6){
                jfz = halfUp5(jfz);
            }
            jfzTotal = jfzTotal.add(jfz);
            volumeSum = volumeSum.add(volume);
            weightSum = weightSum.add(detail.getWeight());
        }
        SuOrder updateOrder = new SuOrder();
        //设置修改的费用
        updateOrder.setBatchNo(order.getBatchNo());
        updateOrder.setAttachFee(vo.getAttachFee());
        updateOrder.setZgFee(vo.getZgFee());
        updateOrder.setSingleOperatFee(vo.getSingleOperatFee());
        updateOrder.setSingleDeclareFee(vo.getSingleDeclareFee());
        updateOrder.setIscog(order.getIscog());
        updateOrder.setBackBoxRemark(vo.getBackBoxRemark());
        updateOrder.setWeightSum(weightSum);
        updateOrder.setVolumeSum(volumeSum);
        updateOrder.setStatus(StatusEnums.WAREHOUSING.getCode());
        //材积、重量变化，需要重新计算计费单价、计费重量、总价
        //计费重量
//        updateOrder.setChargedWeight(this.suCalculateChargedWeight(mmdOrderDetails, mmdRoute));

        if (mmdRoute.getModeId() == 1 && jfzTotal.compareTo(new BigDecimal(100)) == -1){
            //如果是海派，整单不足100KG按100KG算
            jfzTotal = new BigDecimal(100);
        }else if (mmdRoute.getModeId() == 5 && jfzTotal.compareTo(new BigDecimal(23)) == -1){
            //如果是UPS红单，整单不足23KG按23KG算
            jfzTotal = new BigDecimal(23);
        }
        updateOrder.setChargedWeight(jfzTotal.setScale(0, RoundingMode.UP));
        if (mmdRoute.getModeId() == 9){
            if (volumeSum.compareTo(weightSum.divide(new BigDecimal(300))) == 1){
                updateOrder.setChargedWeight(volumeSum);
            }else{
                updateOrder.setChargedWeight(weightSum.divide(new BigDecimal(300), 1, RoundingMode.HALF_UP));
            }
        }
        //计费单价
        updateOrder.setChargedPrice(order.getChargedPrice());
        //计算订单的总价
        updateOrder.setTotalFee(this.suCalculateTotalFee(updateOrder));
        mmdOrderDetails.forEach(detail -> suOrderDetailDao.updateByPrimaryKeySelective(detail));

        List<MmdOrder> orders = mmdOrderDao.listByBatchNo(order.getBatchNo());
        for (MmdOrder mmdOrder : orders) {
            MmdOrder uporder = new MmdOrder();
            uporder.setOrderNo(mmdOrder.getOrderNo());
            uporder.setIsBack(YesNoEnums.YES.getCode());
            mmdOrderDao.updateByPrimaryKeySelective(uporder);
        }
        return suOrderDao.updateByPrimaryKeySelective(updateOrder) == 1;
    }

    @Override
    public OrderBoxDetailVo refreshBoxPrice(OrderBoxDetailVo eo) {
        MmdOrder order = mmdOrderDao.selectByPrimaryKey(eo.getOrderNo());
        if (order == null) {
            throw new GameException(new CODE(9999, "订单不存在"));
        }
        order.setSingleDeclareFee(eo.getSingleDeclareFee());
        order.setSingleOperatFee(eo.getSingleOperatFee());
        order.setZgFee(eo.getZgFee());
        order.setAttachFee(eo.getAttachFee());
        OrderBoxDetailVo vo = new OrderBoxDetailVo();
        List<OrderBoxItemVo> itemVos = JSON.parseArray(eo.getItemStr(), OrderBoxItemVo.class);
        MmdQuotation mmdQuotation = mmdQuotationDao.selectQuotationByRouteNo(order.getRouteNo());
        if (mmdQuotation == null){
            throw new GameException(new CODE(9999, "没有匹配的报价单"));
        }
        MmdRoute mmdRoute = mmdRouteDao.selectByPrimaryKey(order.getRouteNo());
        List<MmdOrderDetailEo> mmdOrderDetails = new ArrayList<>();
        List<OrderBoxItemVo> itemVoResult = new ArrayList<>();
        BigDecimal jfzTotal = BigDecimal.ZERO;
        BigDecimal volumeSum = BigDecimal.ZERO;
        BigDecimal weightSum = BigDecimal.ZERO;
        for (OrderBoxItemVo itemVo : itemVos) {
            MmdOrderDetailEo detail = new MmdOrderDetailEo();
            detail.setPkgNo(itemVo.getPkgNo());
            detail.setLength(itemVo.getLength());
            detail.setBreadth(itemVo.getBreadth());
            detail.setHeight(itemVo.getHeight());
            detail.setWeight(itemVo.getWeight());
            mmdOrderDetails.add(detail);
            //整理返回参数
            OrderBoxItemVo item = new OrderBoxItemVo();
            BeanUtils.copyProperties(detail, item);
            item.setBoxNo(itemVo.getBoxNo());
            BigDecimal volume = BigDecimal.ZERO;
            if ("5".equals(mmdQuotation.getChannelNo()) || "6".equals(mmdQuotation.getChannelNo())) {
                volume = (detail.getLength().multiply(detail.getBreadth()).multiply(detail.getHeight())).divide(new BigDecimal(5000), 2, RoundingMode.HALF_UP);
            }else if ("9".equals(mmdQuotation.getChannelNo())) {
                volume = (detail.getLength().multiply(detail.getBreadth()).multiply(detail.getHeight())).divide(new BigDecimal(1000000), 3, RoundingMode.HALF_UP);
            }else {
                volume = (detail.getLength().multiply(detail.getBreadth()).multiply(detail.getHeight())).divide(new BigDecimal(6000), 2, RoundingMode.HALF_UP);
            }
            if (mmdQuotation.getChannelNo().equals("5") || mmdQuotation.getChannelNo().equals("6")){
                volume = halfUp5(volume);
            }
            item.setVolume(volume);
            BigDecimal jfz = (itemVo.getWeight()==null?BigDecimal.ZERO:itemVo.getWeight()).compareTo(volume==null?BigDecimal.ZERO:volume) == 1 ? itemVo.getWeight() : volume;
            //UPS的计费重要进半位
            if (mmdQuotation.getChannelNo().equals("5") || mmdQuotation.getChannelNo().equals("6")){
                jfz = halfUp5(jfz);
            }

            jfz = getJfz(order.getDestinationCountryId(), mmdQuotation.getChannelNo(), jfz);

            item.setJfz(jfz);
            itemVoResult.add(item);

            jfzTotal = jfzTotal.add(jfz);
            volumeSum = volumeSum.add(volume);
            weightSum = weightSum.add(itemVo.getWeight());
        }
        vo.setItemVos(itemVoResult);
        vo.setOrderNo(order.getOrderNo());
        vo.setRouteNo(order.getRouteNo());
        vo.setFbaAddress(order.getFbaAddress());
        vo.setAttachFee(eo.getAttachFee());
        vo.setSingleDeclareFee(eo.getSingleDeclareFee());
        vo.setSingleOperatFee(eo.getSingleOperatFee());
        vo.setZgFee(eo.getZgFee());
        vo.setChannelNo(mmdQuotation.getChannelNo());
        vo.setBackBoxRemark(order.getBackBoxRemark());
        //材积、重量变化，需要重新计算计费单价、计费重量、总价
        //计费重量
//        BigDecimal bigDecimal = this.calculateChargedWeight(mmdOrderDetails, mmdQuotation);

        if ("9".equals(mmdQuotation.getChannelNo())){
            logger.info("refreshBoxPrice orderNo:{}, weightSum:{}, volumeSum:{}",eo.getOrderNo(),weightSum,volumeSum);
            weightSum = weightSum.divide(new BigDecimal(300), 1, RoundingMode.HALF_UP);
            if (volumeSum.compareTo(weightSum) == 1){
                order.setChargedWeight(volumeSum.setScale(1, RoundingMode.HALF_UP));
                vo.setWeightSum(volumeSum.setScale(1, RoundingMode.HALF_UP));
            }else{
                order.setChargedWeight(weightSum.setScale(1, RoundingMode.HALF_UP));
                vo.setWeightSum(weightSum.setScale(1, RoundingMode.HALF_UP));
            }
        }else{
            jfzTotal = jfzTotal.setScale(0, RoundingMode.UP);

            if ("1".equals(mmdQuotation.getChannelNo()) && jfzTotal.compareTo(new BigDecimal(100)) == -1){
                //如果是海派，整单不足100KG按100KG算
                jfzTotal = new BigDecimal(100);
            }else if ("5".equals(mmdQuotation.getChannelNo()) && jfzTotal.compareTo(new BigDecimal(23)) == -1){
                //如果是UPS红单，整单不足23KG按23KG算
                jfzTotal = new BigDecimal(23);
            }

            vo.setWeightSum(jfzTotal);
            order.setChargedWeight(jfzTotal);
        }

        order.setChargedPrice(order.getChargedPrice());
        //计算订单的总价
        vo.setTotalFee(this.calculateTotalFee(order,mmdQuotation));
        if (StringUtils.isBlank(order.getIscog())) {
            //非单独清关，需要把中港费、单独报关费返回0
            vo.setSingleDeclareFee(BigDecimal.ZERO);
            vo.setZgFee(BigDecimal.ZERO);
        }
        return vo;
    }

    @Override
    public SuOrderBoxDetailVo refreshSuBoxPrice(SuOrderBoxDetailVo eo) {
        SuOrder order = suOrderDao.selectByPrimaryKey(eo.getBatchNo());
        if (order == null) {
            throw new GameException(new CODE(9999, "主订单不存在"));
        }
        order.setSingleDeclareFee(eo.getSingleDeclareFee());
        order.setSingleOperatFee(eo.getSingleOperatFee());
        order.setZgFee(eo.getZgFee());
        order.setAttachFee(eo.getAttachFee());
        SuOrderBoxDetailVo vo = new SuOrderBoxDetailVo();
        List<OrderBoxItemVo> itemVos = JSON.parseArray(eo.getItemStr(), OrderBoxItemVo.class);
        MmdRoute mmdRoute = mmdRouteDao.selectByPrimaryKey(order.getRouteNo());
        List<SuOrderDetail> suOrderDetails = new ArrayList<>();
        List<OrderBoxItemVo> itemVoResult = new ArrayList<>();

        BigDecimal jfzTotal = BigDecimal.ZERO;
        BigDecimal volumeSum = BigDecimal.ZERO;
        BigDecimal weightSum = BigDecimal.ZERO;
        for (OrderBoxItemVo itemVo : itemVos) {
            SuOrderDetail detail = new SuOrderDetail();
            detail.setPkgNo(itemVo.getPkgNo());
            detail.setBoxNo(itemVo.getBoxNo());
            detail.setLength(itemVo.getLength());
            detail.setBreadth(itemVo.getBreadth());
            detail.setHeight(itemVo.getHeight());
            detail.setWeight(itemVo.getWeight());
            suOrderDetails.add(detail);
            //整理返回参数
            OrderBoxItemVo item = new OrderBoxItemVo();
            item.setBoxNo(detail.getBoxNo());
            BeanUtils.copyProperties(detail, item);
            BigDecimal volume = BigDecimal.ZERO;
            if (mmdRoute.getModeId() == 5 || mmdRoute.getModeId() == 6) {
                volume = (detail.getLength().multiply(detail.getBreadth()).multiply(detail.getHeight())).divide(new BigDecimal(5000), 2, RoundingMode.HALF_UP);
            }else if (mmdRoute.getModeId() == 9) {
                volume = (detail.getLength().multiply(detail.getBreadth()).multiply(detail.getHeight())).divide(new BigDecimal(1000000), 3, RoundingMode.HALF_UP);
            }else {
                volume = (detail.getLength().multiply(detail.getBreadth()).multiply(detail.getHeight())).divide(new BigDecimal(6000), 2, RoundingMode.HALF_UP);
            }
            //UPS的材积重要进半位
            if (mmdRoute.getModeId() == 5 || mmdRoute.getModeId() == 6){
                volume = halfUp5(volume);
            }
            BigDecimal jfz = (itemVo.getWeight()==null?BigDecimal.ZERO:itemVo.getWeight()).compareTo(volume==null?BigDecimal.ZERO:volume) == 1 ? itemVo.getWeight() : volume;
            //UPS的计费重要进半位
            if (mmdRoute.getModeId() == 5 || mmdRoute.getModeId() == 6){
                jfz = halfUp5(jfz);
            }

            jfz = getJfz(order.getDestinationCountryId(), String.valueOf(mmdRoute.getModeId()), jfz);

            jfzTotal = jfzTotal.add(jfz);
            volumeSum = volumeSum.add(volume);
            weightSum = weightSum.add(vo.getWeightSum());
            item.setJfz(jfz);
            item.setVolume(volume);
            itemVoResult.add(item);
        }
        vo.setItemVos(itemVoResult);
        vo.setRouteName(mmdRoute.getRouteName());
        vo.setAttachFee(eo.getAttachFee());
        vo.setSingleDeclareFee(eo.getSingleDeclareFee());
        vo.setSingleOperatFee(eo.getSingleOperatFee());
        vo.setZgFee(eo.getZgFee());
        vo.setBackBoxRemark(order.getBackBoxRemark());
        vo.setChannelNo(String.valueOf(mmdRoute.getModeId()));
        //材积、重量变化，需要重新计算计费单价、计费重量、总价
        //计费重量
//        BigDecimal bigDecimal = this.suCalculateChargedWeight(suOrderDetails, mmdRoute);

        if (mmdRoute.getModeId() == 9){
            weightSum = weightSum.divide(new BigDecimal(300), 1, RoundingMode.HALF_UP);
            if (volumeSum.compareTo(weightSum) == 1){
                order.setChargedWeight(volumeSum.setScale(1, RoundingMode.HALF_UP));
                vo.setWeightSum(volumeSum.setScale(1, RoundingMode.HALF_UP));
            }else{
                order.setChargedWeight(weightSum.setScale(1, RoundingMode.HALF_UP));
                vo.setWeightSum(weightSum.setScale(1, RoundingMode.HALF_UP));
            }
        }else{
            jfzTotal = jfzTotal.setScale(0, RoundingMode.UP);

            if (mmdRoute.getModeId() == 1 && jfzTotal.compareTo(new BigDecimal(100)) == -1){
                //如果是海派，整单不足100KG按100KG算
                jfzTotal = new BigDecimal(100);
            }else if (mmdRoute.getModeId() == 5 && jfzTotal.compareTo(new BigDecimal(23)) == -1){
                //如果是UPS红单，整单不足23KG按23KG算
                jfzTotal = new BigDecimal(23);
            }

            vo.setWeightSum(jfzTotal);
            order.setChargedWeight(jfzTotal);
        }

        //计费单价
//        order.setChargedPrice(this.suCalculateUnitPrice(order.getChargedWeight(), order, mmdRoute));
        //计算订单的总价
        vo.setTotalFee(this.suCalculateTotalFee(order));
        if (Objects.equals(order.getIscog(), YesNoEnums.NO.getCode())) {
            //非单独清关，需要把中港费、单独报关费返回0
            vo.setSingleDeclareFee(BigDecimal.ZERO);
            vo.setZgFee(BigDecimal.ZERO);
        }
        return vo;
    }

    @Override
    @Transactional
    public void adminModifyProduct(List<MmdOrderProduct> mmdOrderProductList) {
        for (MmdOrderProduct mmdOrderProduct : mmdOrderProductList) {
            if (mmdOrderProduct.getPid() == null) {
                throw new GameException(new CODE(9999, "请选择产品"));
            }
            MmdOrderProduct product = mmdOrderProductDao.selectByPrimaryKey(mmdOrderProduct.getPid());
            if (product == null) {
                throw new GameException(new CODE(9999, "产品不存在"));
            }
            String level = AdminInterceptor.getUserLoginContext().getLevel();
            if (!"admin".equals(level)) {
                throw new GameException(new CODE(9999, "您没有此修改权限，请联系管理员"));
            }
            checkProduct(mmdOrderProduct);

            //当中英文名、hscode、数量、单价有一个不一样，说明修改了，则新增
            if (!mmdOrderProduct.getProductCnName().equals(product.getProductCnName()) ||
                    !mmdOrderProduct.getProductEnName().equals(product.getProductEnName()) ||
                    !mmdOrderProduct.getHsCode().equals(product.getHsCode()) ||
                    mmdOrderProduct.getCount() != product.getCount() ||
                    mmdOrderProduct.getUnitPrice().compareTo(product.getUnitPrice()) != 0){

                if (product.getIsAdminModifyAfter() == 0) {
                    MmdOrderProduct updateOldProduct = new MmdOrderProduct();
                    updateOldProduct.setPid(mmdOrderProduct.getPid());
                    updateOldProduct.setIsAdminAndSupplyShow(0);
                    mmdOrderProductDao.updateByPrimaryKeySelective(updateOldProduct);

                    MmdOrderProduct updateNewProduct = new MmdOrderProduct();
                    BeanUtils.copyProperties(product, updateNewProduct);
                    updateNewProduct.setPid(UniqueNoUtils.next(UniqueNoUtils.UniqueNoType.P));
                    updateNewProduct.setProductCnName(mmdOrderProduct.getProductCnName());
                    updateNewProduct.setProductEnName(mmdOrderProduct.getProductEnName());
                    updateNewProduct.setHsCode(mmdOrderProduct.getHsCode());
                    updateNewProduct.setCount(mmdOrderProduct.getCount());
                    updateNewProduct.setUnitPrice(mmdOrderProduct.getUnitPrice());
                    updateNewProduct.setIsAdminModifyAfter(1);
                    updateNewProduct.setAdminModifyPid(product.getPid());
                    updateNewProduct.setIsUserShow(0);
                    updateNewProduct.setIsAdminAndSupplyShow(1);
                    updateNewProduct.setCreateTime(new Date());
                    mmdOrderProductDao.insert(updateNewProduct);
                } else {
                    mmdOrderProductDao.updateByPrimaryKeySelective(mmdOrderProduct);
                }
            }
        }
    }

    @Override
    public OrderBoxDetailVo getBoxDetail(String orderNo) {
        MmdOrder order = mmdOrderDao.selectByPrimaryKey(orderNo);
        if (order == null) {
            throw new GameException(new CODE(9999, "订单不存在"));
        }
        OrderBoxDetailVo vo = new OrderBoxDetailVo();
        vo.setBatchNo(order.getBatchNo());
        vo.setOrderNo(order.getOrderNo());
        vo.setRouteNo(order.getRouteNo());
        vo.setFbaAddress(order.getFbaAddress());
        //获取渠道路线费用
        vo.setSingleDeclareFee(order.getSingleDeclareFee());
        vo.setSingleOperatFee(order.getSingleOperatFee());
        vo.setZgFee(order.getZgFee());
        vo.setBackBoxRemark(order.getBackBoxRemark());
        vo.setWeightSum(order.getChargedWeight());
        vo.setTotalFee(order.getTotalFee());
        vo.setAttachFee(order.getAttachFee());

        if (StringUtils.isBlank(order.getIscog())) {
            //非单独清关，需要把中港费、单独报关费返回0
            vo.setSingleDeclareFee(BigDecimal.ZERO);
            vo.setZgFee(BigDecimal.ZERO);
        }
        List<OrderBoxItemVo> itemVos = new ArrayList<>();
        MmdQuotation mmdQuotation = mmdQuotationDao.selectQuotationByRouteNo(order.getRouteNo());
        if (mmdQuotation == null){
            throw new GameException(new CODE(9999, "没有匹配的报价单"));
        }
        BigDecimal weightSum = BigDecimal.ZERO;
        BigDecimal volumeSum = BigDecimal.ZERO;
        //整理箱单
        if (Objects.equals(order.getIsBack(), YesNoEnums.YES.getCode())) {
            //已经回传了箱单，那么就需要把供应商回传的信息拿过来
            List<SuOrderDetail> suOrderDetails = suOrderDetailDao.listByOrderNo(order.getOrderNo());
            BigDecimal jfzTotal = BigDecimal.ZERO;
            for (SuOrderDetail suOrderDetail : suOrderDetails) {
                OrderBoxItemVo itemVo = new OrderBoxItemVo();
                itemVo.setBoxNo(suOrderDetail.getBoxNo());
                itemVo.setPkgNo(suOrderDetail.getPkgNo());
                itemVo.setLength(suOrderDetail.getLength());
                itemVo.setBreadth(suOrderDetail.getBreadth());
                itemVo.setHeight(suOrderDetail.getHeight());
                BigDecimal volume = BigDecimal.ZERO;
                if ("5".equals(mmdQuotation.getChannelNo()) || "6".equals(mmdQuotation.getChannelNo())) {
                    volume = (suOrderDetail.getLength().multiply(suOrderDetail.getBreadth()).multiply(suOrderDetail.getHeight())).divide(new BigDecimal(5000), 2, RoundingMode.HALF_UP);
                }else if ("9".equals(mmdQuotation.getChannelNo())) {
                    volume = (suOrderDetail.getLength().multiply(suOrderDetail.getBreadth()).multiply(suOrderDetail.getHeight())).divide(new BigDecimal(1000000), 3, RoundingMode.HALF_UP);
                }else {
                    volume = (suOrderDetail.getLength().multiply(suOrderDetail.getBreadth()).multiply(suOrderDetail.getHeight())).divide(new BigDecimal(6000), 2, RoundingMode.HALF_UP);
                }
                if (mmdQuotation.getChannelNo().equals("5") || mmdQuotation.getChannelNo().equals("6")){
                    volume = halfUp5(volume);
                }
                itemVo.setVolume(volume);
                itemVo.setWeight(suOrderDetail.getWeight());
                BigDecimal jfz = (itemVo.getWeight()==null?BigDecimal.ZERO:itemVo.getWeight()).compareTo(volume==null?BigDecimal.ZERO:volume) == 1 ? itemVo.getWeight() : volume;
                //UPS的计费重要进半位
                if (mmdQuotation.getChannelNo().equals("5") || mmdQuotation.getChannelNo().equals("6")){
                    jfz = halfUp5(jfz);
                }

                jfz = getJfz(order.getDestinationCountryId(), mmdQuotation.getChannelNo(), jfz);

                jfzTotal = jfzTotal.add(jfz);
                itemVo.setJfz(jfz);
                itemVos.add(itemVo);
                weightSum = weightSum.add(itemVo.getWeight());
                volumeSum = volumeSum.add(itemVo.getVolume());
            }
            //计费重量改变了。重新计算总价
//            vo.setWeightSum(weightSum.compareTo(volumeSum) > 0 ? weightSum.setScale(0,RoundingMode.UP) : volumeSum.setScale(0,RoundingMode.UP));

            if ("1".equals(mmdQuotation.getChannelNo()) && jfzTotal.compareTo(new BigDecimal(100)) == -1){
                //如果是海派，整单不足100KG按100KG算
                jfzTotal = new BigDecimal(100);
            }else if ("5".equals(mmdQuotation.getChannelNo()) && jfzTotal.compareTo(new BigDecimal(23)) == -1){
                //如果是UPS红单，整单不足23KG按23KG算
                jfzTotal = new BigDecimal(23);
            }

            vo.setWeightSum(jfzTotal.setScale(0, RoundingMode.UP));
            order.setChargedWeight(vo.getWeightSum());
            if ("9".equals(mmdQuotation.getChannelNo())){
                weightSum = weightSum.divide(new BigDecimal(300), 1, RoundingMode.HALF_UP);
                if (volumeSum.compareTo(weightSum) == 1){
                    order.setChargedWeight(volumeSum);
                    vo.setWeightSum(volumeSum);
                }else{
                    order.setChargedWeight(weightSum);
                    vo.setWeightSum(weightSum);
                }
            }
            vo.setTotalFee(this.calculateTotalFee(order,mmdQuotation));
            SuOrder suOrder = suOrderDao.selectByPrimaryKey(order.getBatchNo());
            vo.setAttachFee(suOrder.getAttachFee());
            vo.setBackBoxRemark(suOrder.getBackBoxRemark());
            vo.setSingleDeclareFee(suOrder.getSingleDeclareFee());
            vo.setSingleOperatFee(suOrder.getSingleOperatFee());
            vo.setZgFee(suOrder.getZgFee());
        } else {
            MmdOrderDetail mmdOrderDetail = new MmdOrderDetail();
            mmdOrderDetail.setOrderNo(orderNo);
            List<MmdOrderDetail> detailList = mmdOrderDetailDao.selectByKeySelective(mmdOrderDetail);
            for (MmdOrderDetail detail : detailList) {
                OrderBoxItemVo itemVo = new OrderBoxItemVo();
                itemVo.setBoxNo(detail.getBoxNo());
                itemVo.setPkgNo(detail.getPkgNo());
                itemVo.setLength(detail.getLength());
                itemVo.setBreadth(detail.getBreadth());
                itemVo.setHeight(detail.getHeight());
                BigDecimal volume = BigDecimal.ZERO;
                if ("5".equals(mmdQuotation.getChannelNo()) || "6".equals(mmdQuotation.getChannelNo())) {
                    volume = (detail.getLength().multiply(detail.getBreadth()).multiply(detail.getHeight())).divide(new BigDecimal(5000), 2, RoundingMode.HALF_UP);
                }else if ("9".equals(mmdQuotation.getChannelNo())) {
                    volume = (detail.getLength().multiply(detail.getBreadth()).multiply(detail.getHeight())).divide(new BigDecimal(1000000), 3, RoundingMode.HALF_UP);
                }else {
                    volume = (detail.getLength().multiply(detail.getBreadth()).multiply(detail.getHeight())).divide(new BigDecimal(6000), 2, RoundingMode.HALF_UP);
                }
                if (mmdQuotation.getChannelNo().equals("5") || mmdQuotation.getChannelNo().equals("6")){
                    volume = halfUp5(volume);
                }
                itemVo.setVolume(volume);
                itemVo.setWeight(detail.getWeight());
                BigDecimal jfz = (itemVo.getWeight()==null?BigDecimal.ZERO:itemVo.getWeight()).compareTo(volume==null?BigDecimal.ZERO:volume) == 1 ? itemVo.getWeight() : volume;
                //UPS的计费重要进半位
                if (mmdQuotation.getRouteNo().contains("UPS") ||mmdQuotation.getRouteName().contains("UPS")){
                    jfz = halfUp5(jfz);
                }
                jfz = getJfz(order.getDestinationCountryId(), mmdQuotation.getChannelNo(), jfz);

                itemVo.setJfz(jfz);
                itemVos.add(itemVo);
            }
        }
        vo.setChannelNo(mmdQuotation.getChannelNo());
        vo.setItemVos(itemVos);
        return vo;
    }

    private BigDecimal getJfz(Long destinationCountryId, String channelNo, BigDecimal jfz){
        if (usCountryIdList.contains(destinationCountryId) && ("1".equals(channelNo) || "2".equals(channelNo))){
            if (jfz.compareTo(new BigDecimal(10)) == -1){
                jfz = new BigDecimal(10);
            }
        }
        //如果是欧洲海运/空运，计费重不足12kg，按12kg算
        else if (europeCountryIdList.contains(destinationCountryId) && ("1".equals(channelNo) || "2".equals(channelNo))){
            if (jfz.compareTo(new BigDecimal(12)) == -1){
                jfz = new BigDecimal(12);
            }
        }
        return jfz;
    }

    @Override
    public List<MmdLogistics> getLogisticsList() {
        List<MmdLogistics> mmdLogistics = mmdLogisticsDao.selectByKeySelective(null);
        return mmdLogistics;
    }


    @Override
    public OrderVo getOrderDetail(String orderNo) {
        MmdOrder order = mmdOrderDao.selectByPrimaryKey(orderNo);
        if (order == null) {
            throw new GameException(new CODE(9999, "订单不存在"));
        }
        OrderVo vo = new OrderVo();
        BeanUtils.copyProperties(order, vo);

        logger.info("###订单区域1{}", JSON.toJSONString(order.getDestinationCountryId()));
        MmdArea areaById = areaDao.getAreaById(order.getDestinationCountryId());
        logger.info("###订单区域2{}", JSON.toJSONString(areaById));
        vo.setDestinationCountryId(areaById.getParentAreaId());
        if (StringUtils.isNotBlank(order.getIscog())) {
            List<String> iscogs = Splitter.on(",").splitToList(order.getIscog());
            vo.setIscog(iscogs);
        }
        MmdFba mmdFba = mmdFbaDao.selectByPrimaryKey(order.getFbaDepotNo());
        if (mmdFba != null) {
            vo.setFbaCountry(mmdFba.getAreaName());
        }
        String level = AdminInterceptor.getUserLoginContext().getLevel();

        List<MmdOrderDetailVo> mmdOrderDetails = mmdOrderDetailDao.list(orderNo);

        for (MmdOrderDetailVo mmdOrderDetail : mmdOrderDetails) {
            List<MmdOrderProduct> list = mmdOrderProductDao.list(mmdOrderDetail.getPkgNo(),level);
            mmdOrderDetail.setProductEo(list);
        }
        vo.setDetails(mmdOrderDetails);
        return vo;
    }

    @Override
    public List<MmdOrderDetailVo> getCustomOrderBoxDetail(String orderNo) {
        MmdOrder order = mmdOrderDao.selectByPrimaryKey(orderNo);
        if (order == null) {
            throw new GameException(new CODE(9999, "订单不存在"));
        }

        List<MmdOrderDetailVo> mmdOrderDetails = mmdOrderDetailDao.list(orderNo);

        for (MmdOrderDetailVo mmdOrderDetail : mmdOrderDetails) {
            List<MmdOrderProduct> list = mmdOrderProductDao.customList(mmdOrderDetail.getPkgNo());
            mmdOrderDetail.setProductEo(list);
        }
        return mmdOrderDetails;
    }

    @Override
    @Transactional
    public boolean auditOrder(String orderNo, Integer flag) {
        MmdOrder mmdOrder = mmdOrderDao.selectByPrimaryKey(orderNo);
        if (mmdOrder == null) {
            throw new GameException(new CODE(9999, "订单不存在"));
        }
        if (!StatusEnums.WAITAUDIT.getCode().equals(mmdOrder.getStatus())) {
            throw new GameException(new CODE(9999, "订单不在待审核状态"));
        }
        MmdOrder update = new MmdOrder();
        update.setOrderNo(orderNo);
        if (flag == 0) {
            update.setStatus(StatusEnums.AUFIT_FAIL.getCode());
        } else {
            update.setStatus(StatusEnums.AUDIT.getCode());
        }

        return mmdOrderDao.updateByPrimaryKeySelective(update) == 1;
    }


    @Override
    public TracesVo getOrderLogisticsDetail(String orderNo) {
        TracesVo vo = new TracesVo();
        MmdOrder order = mmdOrderDao.selectByPrimaryKey(orderNo);
        List<Traces> traces = new ArrayList<>();

        //查询当前订单号的提单物流轨迹
        List<Traces> list = mmdOrderDao.listDeliveryTrace(orderNo);
        for (Traces traces1 : list) {
            if (traces1 != null && traces1.getAcceptTime() != null) {
                traces.addAll(list);
            }
        }
        vo.setOrderNo(orderNo);
        vo.setLogisticsNo(order.getLogisticsNo());
        vo.setLogisticsCompanyName(order.getLogisticsCompanyName());
        MmdOrderLogistics logistics = mmdOrderLogisticsDao.selectByPrimaryKey(orderNo);
        if (logistics != null) {
            List<Traces> beforeTraces = JSON.parseArray(logistics.getLogistics(), Traces.class);
            traces.addAll(beforeTraces);
        }
        traces = traces.stream().sorted(Comparator.comparing(Traces::getAcceptTime).reversed()).collect(Collectors.toList());
        vo.setTraces(traces);
        return vo;
    }

    @Override
    public void pullLogisticsInfo() {
        List<MmdOrder> list = mmdOrderDao.selectNoSign();
        for (MmdOrder order : list) {
            pullLogisticsInfoService.pull(order);
        }
    }


    @Override
    @Transactional
    public boolean mergeOrder(String orderNos) {
        if (StringUtils.isBlank(orderNos)) {
            throw new GameException(new CODE(9999, "请选择合并订单"));
        }
        if (!orderNos.contains(",")) {
            throw new GameException(new CODE(9999, "请至少选择一个订单"));
        }
        List<String> orderNoList = Splitter.on(",").splitToList(orderNos);

        Set<String> postcode = new HashSet<>();
        Set<String> routeNo = new HashSet<>();
        //非单独报关 不要上传文件
        Set<String> noIscogSet = new HashSet<>();
        Set<String> yesIscogSet = new HashSet<>();
        for (int i = 0; i < orderNoList.size(); i++) {
            String orderNo = orderNoList.get(i);
            MmdOrder order = mmdOrderDao.selectByPrimaryKey(orderNo);
            postcode.add(order.getFbaPostcode());
            if (postcode.size() > 1) {
                throw new GameException(new CODE(9999, "订单" + orderNo + "邮编不一致，无法合单"));
            }
            routeNo.add(order.getRouteNo());
            if (routeNo.size() > 1) {
                throw new GameException(new CODE(9999, "订单" + orderNo + "渠道路线不一致，无法合单"));
            }
            if (StringUtils.isNotBlank(order.getIscog())) {
                //单独报关
                yesIscogSet.add(orderNo);
            }
            if (StringUtils.isBlank(order.getIscog())) {
                //非单独报关
                noIscogSet.add(orderNo);
            }
            if (noIscogSet.size() > 0 && yesIscogSet.size() > 0) {
                throw new GameException(new CODE(9999, "合单订单中存在是否单独报关不一致的情况，请重新选择"));
            }
        }

        //生成批次号
        String batchNo = UniqueNoUtils.next(UniqueNoUtils.UniqueNoType.B);

        for (String s : orderNoList) {
            MmdOrder order = new MmdOrder();
            order.setOrderNo(s);
            order.setBatchNo(batchNo);
            mmdOrderDao.updateByPrimaryKeySelective(order);
        }
        return true;
    }

    @Override
    @Transactional
    public boolean splitOrder(String pkgNos, String orderNo) {
        if (StringUtils.isBlank(pkgNos)) {
            throw new GameException(new CODE(9999, "请选择拆分的箱单"));
        }
        MmdOrder order = mmdOrderDao.selectByPrimaryKey(orderNo);
        if (order == null) {
            throw new GameException(new CODE(9999, "原订单不存在"));
        }
        MmdOrder oldUpdate = new MmdOrder();
        oldUpdate.setOrderNo(orderNo);
        oldUpdate.setIsSplit(YesNoEnums.YES.getCode());
        mmdOrderDao.updateByPrimaryKeySelective(oldUpdate);

        //生成独立出来的订单
        MmdOrder newOrder = new MmdOrder();
        BeanUtils.copyProperties(order, newOrder);
        //生成批次号
        String newOrderNo = null;
        for (int i = 1; i < 100; i++) {
            MmdOrder order1 = mmdOrderDao.selectByPrimaryKey(orderNo + "_" + i);
            if (order1 == null) {
                newOrderNo = orderNo + "_" + i;
                break;
            }
        }
        newOrder.setOrderNo(newOrderNo);
        newOrder.setBatchNo(newOrderNo);
        newOrder.setIsSplit(YesNoEnums.YES.getCode());
        newOrder.setCreateTime(new Date());
        newOrder.setIsDelete(0);
        mmdOrderDao.insert(newOrder);

        String level = AdminInterceptor.getUserLoginContext().getLevel();

        List<String> pkgNoList = Splitter.on(",").splitToList(pkgNos);
        for (String pkgNo : pkgNoList) {
            MmdOrderDetail detail = new MmdOrderDetail();
            detail.setOrderNo(newOrderNo);
            detail.setPkgNo(pkgNo);
            mmdOrderDetailDao.updateByPrimaryKeySelective(detail);

            List<MmdOrderProduct> list = mmdOrderProductDao.list(pkgNo, level);
            for (MmdOrderProduct mmdOrderProduct : list) {
                MmdOrderProduct updateProduct = new MmdOrderProduct();
                updateProduct.setOrderNo(newOrderNo);
                updateProduct.setPid(mmdOrderProduct.getPid());
                mmdOrderProductDao.updateByPrimaryKeySelective(mmdOrderProduct);
            }
        }

        //重新计算原单的费用
        refreshOrderFee(orderNo);
        //重新计算新分单的费用
        refreshOrderFee(newOrderNo);

        return true;
    }


    /**
     * 更新订单的相关价格
     */
    private void refreshOrderFee(String orderNo) {
        MmdOrder order = mmdOrderDao.selectByPrimaryKey(orderNo);
        MmdQuotation mmdQuotation = mmdQuotationDao.selectQuotationByRouteNo(order.getRouteNo());
        if (mmdQuotation == null){
            throw new GameException(new CODE(9999, "没有匹配的报价单"));
        }

        //配置装箱单
        List<MmdOrderDetailVo> list = mmdOrderDetailDao.list(orderNo);
        List<MmdOrderDetailEo> newOrderDetail = new ArrayList<>();
        for (MmdOrderDetailVo mmdOrderDetailVo : list) {
            MmdOrderDetailEo eo = new MmdOrderDetailEo();
            BeanUtils.copyProperties(mmdOrderDetailVo, eo);
            newOrderDetail.add(eo);
        }

        //计费重量
        order.setChargedWeight(this.calculateChargedWeight(order, newOrderDetail, mmdQuotation));
        //计算订单的总价
        order.setTotalFee(this.calculateTotalFee(order,mmdQuotation));
        mmdOrderDao.updateByPrimaryKeySelective(order);
    }


    @Override
    @Transactional
    public boolean chooseSupplier(String orderNo, String supplierCode, String routeNo) {
        MmdOrder order = mmdOrderDao.selectByPrimaryKey(orderNo);
        if (order == null) {
            throw new GameException(new CODE(9999, "订单不存在"));
        }
        MmdRoute mmdRoute = mmdRouteDao.selectByPrimaryKey(routeNo);
        if (mmdRoute == null) {
            throw new GameException(new CODE(9999, "供应商路线不存在"));
        }
        MmdSupplier mmdSupplier = mmdSupplierDao.selectByPrimaryKey(supplierCode);
        if (mmdSupplier == null) {
            throw new GameException(new CODE(9999, "供应商不存在"));
        }
        if (!mmdSupplier.getSupplierCode().equals(mmdRoute.getSupplierCode())) {
            throw new GameException(new CODE(9999, "供应商路线不属于该供应商"));
        }
        List<SuOrderDetail> suOrder1 = suOrderDetailDao.listByOrderNo(order.getOrderNo());
        if (!CollectionUtils.isEmpty(suOrder1)) {
            throw new GameException(new CODE(9999, "该订单已指定供应商"));
        }
        //当前被指定订单的总重、材积
        BigDecimal currWeight = BigDecimal.ZERO;
        BigDecimal currVolume = BigDecimal.ZERO;
        List<MmdOrderDetailVo> currOrderDetails = mmdOrderDetailDao.list(orderNo);
        for (MmdOrderDetailVo mmdOrderDetailVo : currOrderDetails) {
            currWeight = currWeight.add(mmdOrderDetailVo.getWeight());
            currVolume = currVolume.add(this.calculateVolume(mmdOrderDetailVo, mmdRoute));
            SuOrderDetail suOrderDetail = new SuOrderDetail();
            BeanUtils.copyProperties(mmdOrderDetailVo, suOrderDetail);
            suOrderDetail.setBatchNo(order.getBatchNo());
            suOrderDetailDao.insert(suOrderDetail);
        }
        MmdOrder mmdOrder = new MmdOrder();
        mmdOrder.setOrderNo(orderNo);
        mmdOrder.setChooseSup(YesNoEnums.YES.getCode());
        mmdOrderDao.updateByPrimaryKeySelective(mmdOrder);

        SuOrder beforeSuOrder = suOrderDao.selectByPrimaryKey(order.getBatchNo());
        //本次账单的交易金额
        BigDecimal currAmount = BigDecimal.ZERO;
        BigDecimal beforeAmount = BigDecimal.ZERO;

        if (beforeSuOrder == null) {
            //该批次号还没指定供应商
            SuOrder newSuOrder = new SuOrder();
            newSuOrder.setStatus(StatusEnums.AUDIT.getCode());
            newSuOrder.setIscog(YesNoEnums.NO.getCode());
            if (StringUtils.isNotBlank(order.getIscog())) {
                newSuOrder.setIscog(YesNoEnums.YES.getCode());
            }
            newSuOrder.setBatchNo(order.getBatchNo());
            newSuOrder.setUid(mmdSupplier.getAccountUid());
            newSuOrder.setSupplierCode(supplierCode);
            newSuOrder.setRouteNo(routeNo);
            newSuOrder.setRouteName(mmdRoute.getRouteName());
            newSuOrder.setCreateTime(new Date());
            newSuOrder.setFbaDepotNo(order.getFbaDepotNo());
            newSuOrder.setFbaPostcode(order.getFbaPostcode());
            newSuOrder.setDestinationCountryId(order.getDestinationCountryId());
            newSuOrder.setDestinationCountry(order.getDestinationCountry());
            List<MmdRouteDetail> routeDetail = routeDetailDao.getRouteDetail(mmdRoute.getRouteNo());
            if (!CollectionUtils.isEmpty(routeDetail)) {
                //一条路线，单票操作费、单票报关费、中港费都是一样的
                MmdRouteDetail mmdRouteDetail = routeDetail.get(0);
                newSuOrder.setSingleDeclareFee(mmdRouteDetail.getSingleDeclareFee());
                newSuOrder.setSingleOperatFee(mmdRouteDetail.getSingleOperatFee());
                newSuOrder.setZgFee(mmdRouteDetail.getZgFee());
            }
            //采用供应商的相关信息重新计算计费单价、附加费、总价。
            //计算总材积、总重量，设置计费重量
            newSuOrder.setWeightSum(currWeight);
            newSuOrder.setVolumeSum(currVolume);
            //总的计费重需要向上取整
            BigDecimal chargeWeight = currVolume.compareTo(currWeight) > 0 ? currVolume : currWeight;
            chargeWeight = chargeWeight.setScale(0, RoundingMode.UP);
            newSuOrder.setChargedWeight(chargeWeight);

            //计费单价
            newSuOrder.setChargedPrice(this.calculateSuUnitPrice(newSuOrder.getChargedWeight(), mmdRoute, order.getDestinationCountryId()));
            //计算附加费
            MmdOrderProduct product = new MmdOrderProduct();
            product.setOrderNo(order.getOrderNo());
            List<MmdOrderProduct> productList = mmdOrderProductDao.selectByKeySelective(product);
            newSuOrder.setAttachFee(this.calculateSuAttachFee(mmdRoute, productList));
            //计算订单的总价
            newSuOrder.setTotalFee(this.calculateSuTotalFee(newSuOrder, order));
            currAmount = newSuOrder.getTotalFee();
            suOrderDao.insert(newSuOrder);
        } else {
            //记录新的订单录入前该主单号对应的总价
            beforeAmount = beforeSuOrder.getTotalFee();
            //已存在该批次号指定供应商
            beforeSuOrder.setVolumeSum(beforeSuOrder.getVolumeSum().add(currVolume));
            beforeSuOrder.setWeightSum(beforeSuOrder.getWeightSum().add(currWeight));
            //1.重新计算计费重量
            //总的计费重需要向上取整
            BigDecimal chargeWeight = beforeSuOrder.getChargedWeight().add(currVolume.compareTo(currWeight) > 0 ? currVolume : currWeight);
            chargeWeight = chargeWeight.setScale(0, RoundingMode.UP);
            beforeSuOrder.setChargedWeight(chargeWeight);
            //2.重新获取当前总单的计费单价
            beforeSuOrder.setChargedPrice(this.calculateSuUnitPrice(beforeSuOrder.getChargedWeight(), mmdRoute, order.getDestinationCountryId()));
            //3.重新计算附加费
            List<MmdOrder> list = mmdOrderDao.listByBatchNo(beforeSuOrder.getBatchNo());
            list.add(order);
            //获取该批次号所有已经指定供应商的订单的hscode
            List<MmdOrderProduct> productList = new ArrayList<>();
            String level = AdminInterceptor.getUserLoginContext().getLevel();
            for (MmdOrder mmdOrder1 : list) {
                productList.addAll(mmdOrderProductDao.listByOrderNo(mmdOrder1.getOrderNo(), level));
            }
            beforeSuOrder.setAttachFee(this.calculateSuAttachFee(mmdRoute, productList));
            //4.重新计算总价
            beforeSuOrder.setTotalFee(this.calculateSuTotalFee(beforeSuOrder, order));
            currAmount = beforeSuOrder.getTotalFee();
            suOrderDao.updateByPrimaryKeySelective(beforeSuOrder);
        }
        //保存账单的账单
        MmdBillRecord record = new MmdBillRecord();
        record.setBusinessNo(order.getBatchNo());
        record.setCreateTime(new Date());
        record.setUserType(UserTypeEnums.SUP.getCode());
        record.setUid(mmdSupplier.getAccountUid());
        record.setAmcount(currAmount);
        record.setType(BillTypeEnums.CONSUMER.getCode());

        MmdBillRecord maxRecord = mmdBillRecordDao.selectMaxBill(mmdSupplier.getAccountUid());
        record.setTotalAmount(currAmount);
        record.setRemark(order.getOrderNo() + "推送供应商");
        if (maxRecord != null) {
            record.setTotalAmount(maxRecord.getTotalAmount().subtract(beforeAmount).add(currAmount));
        }
        mmdBillRecordDao.insert(record);
        return true;
    }

    /**
     * 计算单行的材积
     *
     * @param mmdOrderDetailVo
     * @param mmdRoute
     * @return
     */
    private BigDecimal calculateVolume(MmdOrderDetailVo mmdOrderDetailVo, MmdRoute mmdRoute) {
        BigDecimal volume = BigDecimal.ZERO;
        //5-UPS红单,6-UPS蓝单
        if ("5".equals(mmdRoute.getModeId()) || "6".equals(mmdRoute.getModeId())) {
            volume = (mmdOrderDetailVo.getLength().multiply(mmdOrderDetailVo.getBreadth()).multiply(mmdOrderDetailVo.getHeight())).divide(new BigDecimal(5000), 2, BigDecimal.ROUND_UP);
        } else {
            volume = (mmdOrderDetailVo.getLength().multiply(mmdOrderDetailVo.getBreadth()).multiply(mmdOrderDetailVo.getHeight())).divide(new BigDecimal(6000), 2, BigDecimal.ROUND_UP);
        }
        return volume;
    }

    @Override
    public QuerySuOrderListVo supplierOrderList(SuOrderQueryEo eo) {
        logger.info("查询供应商订单列表参数：{}", JSON.toJSONString(eo));
        MmdUser mmdUser = userDao.selectByPrimaryKey(eo.getUid());
        if (mmdUser == null) {
            throw new GameException(new CODE(9999, "请登录"));
        }
        if (eo.getStartOrderTime() != null && eo.getEndOrderTime() != null && eo.getStartOrderTime().after(eo.getEndOrderTime())) {
            throw new GameException(new CODE(9999, "请选择正确的时间段"));
        }

        SupplierVo supplierDetailByUid = mmdSupplierDao.getSupplierDetailByUid(mmdUser.getUid());
        if (supplierDetailByUid == null) {
            throw new GameException(new CODE(9999, "请使用供应商账号登录"));
        }
        eo.setSupplierCode(supplierDetailByUid.getSupplierCode());

        String level = AdminInterceptor.getUserLoginContext().getLevel();

        QuerySuOrderListVo vo = new QuerySuOrderListVo();
        List<SuOrderVo> suOrders = suOrderDao.suOrderList(eo);
        OrderListGoodsDetailVo goodsDetail = null;
        BigDecimal weightSum = BigDecimal.ZERO;
        BigDecimal volumeSum = BigDecimal.ZERO;
        BigDecimal bulkSum = BigDecimal.ZERO;
        for (SuOrderVo suOrderVo : suOrders) {
            StatusEnums statusEnum = StatusEnums.getStatusEnum(suOrderVo.getStatus());
            suOrderVo.setStatusDesc(statusEnum == null ? "" : statusEnum.getName());
            BigDecimal singleBulkSum = BigDecimal.ZERO;

            //组装单个订单数据
            MmdRoute mmdRoute = mmdRouteDao.selectByPrimaryKey(suOrderVo.getRouteNo());
            List<MmdRouteHscode> mmdRouteHscodes = routeHscodeDao.selectListByHsCode(mmdRoute.getRouteNo(), new ArrayList<>());
            Map<String, BigDecimal> hscodeMapResult = new HashMap<>();
            if (!CollectionUtils.isEmpty(mmdRouteHscodes)) {
                Map<String, BigDecimal> hscodeMap = mmdRouteHscodes.stream().collect(Collectors.toMap(MmdRouteHscode::getHscode, MmdRouteHscode::getAttachFee));
                if (!hscodeMap.isEmpty()) {
                    hscodeMapResult.putAll(hscodeMap);
                }
            }
            List<MmdOrder> orders = mmdOrderDao.listByBatchNo(suOrderVo.getBatchNo());
            List<OrderListGoodsDetailVo> goodsDetails = new ArrayList<>();
            for (MmdOrder order : orders) {
                List<SuOrderDetail> suOrderDetails = suOrderDetailDao.listByOrderNo(order.getOrderNo());
                for (SuOrderDetail mmdOrderDetailVo : suOrderDetails) {
                    List<MmdOrderProduct> list2 = mmdOrderProductDao.list(mmdOrderDetailVo.getPkgNo(), level);
                    for (MmdOrderProduct mmdOrderProduct : list2) {
                        goodsDetail = new OrderListGoodsDetailVo();
                        goodsDetail.setPid(mmdOrderProduct.getPid());
                        goodsDetail.setOrderNo(mmdOrderDetailVo.getOrderNo());
                        goodsDetail.setPkgNo(mmdOrderProduct.getPkgNo());
                        goodsDetail.setBoxNo(mmdOrderProduct.getBoxNo());
                        goodsDetail.setHsCode(mmdOrderProduct.getHsCode());
                        goodsDetail.setIsem(mmdOrderProduct.getIsem());
                        goodsDetail.setProductCnName(mmdOrderProduct.getProductCnName());
                        goodsDetail.setAttachFee(hscodeMapResult.getOrDefault(mmdOrderProduct.getHsCode(), BigDecimal.ZERO));
                        goodsDetail.setLength(mmdOrderDetailVo.getLength());
                        goodsDetail.setWeight(mmdOrderDetailVo.getWeight());
                        goodsDetail.setBreadth(mmdOrderDetailVo.getBreadth());
                        goodsDetail.setHeight(mmdOrderDetailVo.getHeight());
                        goodsDetails.add(goodsDetail);
                    }
                    singleBulkSum = singleBulkSum.add(mmdOrderDetailVo.getLength().multiply(mmdOrderDetailVo.getBreadth()).multiply(mmdOrderDetailVo.getHeight()));
                }
            }
            suOrderVo.setGoodsDetailList(goodsDetails);
            if (StringUtils.isBlank(suOrderVo.getDeliveryNo())) {
                weightSum = weightSum.add(suOrderVo.getWeightSum());
                volumeSum = volumeSum.add(suOrderVo.getVolumeSum());
                bulkSum = bulkSum.add(singleBulkSum);
            }
        }
        vo.setSuOrderVoList(suOrders);
        vo.setBulkSum(bulkSum);
        vo.setVolumeSum(volumeSum);
        vo.setWeightSum(weightSum);
        return vo;
    }

    @Override
    public void exportOrder(SuOrderQueryEo eo, HttpServletRequest request, HttpServletResponse response) {
        InputStream in = getClass().getResourceAsStream("/excel/orderList.xlsx");
        try {
            XSSFWorkbook xWorkbook = new XSSFWorkbook(in);
            Sheet receiveSheet = xWorkbook.getSheetAt(0);
            xWorkbook.setSheetName(0, "订单列表");
            //查询导出数据列表
            List<ExportOrderVo> orderList = getExportList(eo);
            //设置导出信息
            setSheet(receiveSheet, orderList);

            //byte[] export1 = ExcelUtil.export(xWorkbook);
            String fileName = "订单列表" + DateUtil.date2String(new Date(), DateUtil.yyyyMMddHHmmss) + ".xlsx";
            String agent = request.getHeader("User-Agent");
            boolean isMSIE = (agent != null && agent.contains("MSIE"));
            if (isMSIE) {
                fileName = java.net.URLEncoder.encode(fileName, "UTF8");
            } else {
                //兼容火狐，否则中文乱码
                fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
            }
            response.reset();
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("UTF-8");
            response.setHeader("content-Disposition", "attachment;filename=" + fileName);
            OutputStream os = response.getOutputStream();
            xWorkbook.write(os);
            os.flush();
            os.close();
        } catch (Exception e) {
            logger.error("导出异常###", e);
            throw new GameException(new CODE(9999, "导出失败"));
        }
    }

    @Override
    public void exportAdminOrder(MyOrderQueryEo eo, HttpServletRequest request, HttpServletResponse response) {
        InputStream in = getClass().getResourceAsStream("/excel/orderList.xlsx");
        try {
            XSSFWorkbook xWorkbook = new XSSFWorkbook(in);
            Sheet receiveSheet = xWorkbook.getSheetAt(0);
            xWorkbook.setSheetName(0, "订单列表");
            //查询导出数据列表
            List<ExportOrderVo> orderList = getExportAdminOrderList(eo);
            //设置导出信息
            setSheet(receiveSheet, orderList);

            //byte[] export1 = ExcelUtil.export(xWorkbook);
            String fileName = "订单列表" + DateUtil.date2String(new Date(), DateUtil.yyyyMMddHHmmss) + ".xlsx";
            String agent = request.getHeader("User-Agent");
            boolean isMSIE = (agent != null && agent.contains("MSIE"));
            if (isMSIE) {
                fileName = java.net.URLEncoder.encode(fileName, "UTF8");
            } else {
                //兼容火狐，否则中文乱码
                fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
            }
            response.reset();
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("UTF-8");
            response.setHeader("content-Disposition", "attachment;filename=" + fileName);
            OutputStream os = response.getOutputStream();
            xWorkbook.write(os);
            os.flush();
            os.close();
        } catch (Exception e) {
            logger.error("导出异常###", e);
            throw new GameException(new CODE(9999, "导出失败"));
        }
    }

    @Override
    public void downloadTrackingTemplate(HttpServletRequest request, HttpServletResponse response) {
        InputStream in = getClass().getResourceAsStream("/excel/waybill.xlsx");
        try {
            XSSFWorkbook xWorkbook = new XSSFWorkbook(in);

            String fileName = "转单号导入模板.xlsx";
            String agent = request.getHeader("User-Agent");
            boolean isMSIE = (agent != null && agent.contains("MSIE"));
            if (isMSIE) {
                fileName = java.net.URLEncoder.encode(fileName, "UTF8");
            } else {
                //兼容火狐，否则中文乱码
                fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
            }
            response.reset();
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("UTF-8");
            response.setHeader("content-Disposition", "attachment;filename=" + fileName);
            OutputStream os = response.getOutputStream();
            xWorkbook.write(os);
            os.flush();
            os.close();
        } catch (Exception e) {
            logger.error("下载异常###", e);
            throw new GameException(new CODE(9999, "下载失败"));
        }
    }

    /**
     * 获取导出订单列表
     *
     * @param eo
     * @return
     */
    private List<ExportOrderVo> getExportList(SuOrderQueryEo eo) {
        logger.info("查询供应商订单列表参数：{}", JSON.toJSONString(eo));
        MmdUser mmdUser = userDao.selectByPrimaryKey(eo.getUid());
        if (mmdUser == null) {
            throw new GameException(new CODE(9999, "请登录"));
        }
        if (eo.getStartOrderTime() != null && eo.getEndOrderTime() != null && eo.getStartOrderTime().after(eo.getEndOrderTime())) {
            throw new GameException(new CODE(9999, "请选择正确的时间段"));
        }

        SupplierVo supplierDetailByUid = mmdSupplierDao.getSupplierDetailByUid(mmdUser.getUid());
        if (supplierDetailByUid == null) {
            throw new GameException(new CODE(9999, "请使用供应商账号登录"));
        }
        eo.setSupplierCode(supplierDetailByUid.getSupplierCode());

        String level = AdminInterceptor.getUserLoginContext().getLevel();

        List<ExportOrderVo> vos = new ArrayList<>();
        ExportOrderVo vo = null;
        List<SuOrderVo> orderList = suOrderDao.suOrderList(eo);
        for (SuOrderVo suOrder : orderList) {
            List<MmdOrder> orders = mmdOrderDao.listByBatchNo(suOrder.getBatchNo());
            for (MmdOrder order : orders) {
                List<MmdOrderDetailVo> detailList = mmdOrderDetailDao.list(order.getOrderNo());
                for (MmdOrderDetailVo mmdOrderDetailVo : detailList) {
                    List<MmdOrderProduct> productList = mmdOrderProductDao.list(mmdOrderDetailVo.getPkgNo(), level);
                    for (MmdOrderProduct mmdOrderProduct : productList) {
                        vo = new ExportOrderVo();
                        vo.setBatchNo(order.getBatchNo());
                        vo.setOrderNo(order.getOrderNo());
                        vo.setBoxNo(mmdOrderDetailVo.getBoxNo());
                        vo.setProductCnName(mmdOrderProduct.getProductCnName());
                        vo.setProductEnName(mmdOrderProduct.getProductEnName());
                        vo.setHsCode(mmdOrderProduct.getHsCode());
                        vo.setLength(mmdOrderDetailVo.getLength());
                        vo.setBreadth(mmdOrderDetailVo.getBreadth());
                        vo.setHeight(mmdOrderDetailVo.getHeight());
                        vo.setCount(mmdOrderProduct.getCount());
                        vo.setBulk(mmdOrderDetailVo.getLength().multiply(mmdOrderDetailVo.getBreadth()).multiply(mmdOrderDetailVo.getHeight()).setScale(2, BigDecimal.ROUND_UP));
                        vo.setWeight(mmdOrderDetailVo.getWeight());
                        vo.setUnitPrice(mmdOrderProduct.getUnitPrice());
                        vo.setMaterialCnName(mmdOrderProduct.getMaterialCnName() + "|" + mmdOrderProduct.getMaterialEnName());
                        vo.setUseCnName(mmdOrderProduct.getUseCnName() + "|" + mmdOrderProduct.getUseEnName());
                        vo.setType(mmdOrderProduct.getType());
                        vo.setBrand(mmdOrderProduct.getBrand());
                        vo.setFbaPostcode(order.getFbaPostcode());
                        vo.setFbaDepotNo(order.getFbaDepotNo());
                        vo.setFbaLinkman(order.getFbaLinkman());
                        vo.setFbaTel(order.getFbaTel());
                        vo.setFbaAddress(order.getFbaAddress());
                        vos.add(vo);
                    }
                }
            }
        }
        return vos;
    }

    /**
     * 获取导出订单列表
     *
     * @param eo
     * @return
     */
    private List<ExportOrderVo> getExportAdminOrderList(MyOrderQueryEo eo) {
        logger.info("导出admin订单列表参数：{}", JSON.toJSONString(eo));
        MmdUser mmdUser = userDao.selectByPrimaryKey(eo.getUid());
        if (mmdUser == null) {
            throw new GameException(new CODE(9999, "请登录"));
        }
        if (!mmdUser.getLevel().equals("admin"))
        {
            throw new GameException(new CODE(9999, "请登录管理员账号"));
        }
        if (eo.getStartOrderTime() != null && eo.getEndOrderTime() != null && eo.getStartOrderTime().after(eo.getEndOrderTime())) {
            throw new GameException(new CODE(9999, "请选择正确的时间段"));
        }

        String level = AdminInterceptor.getUserLoginContext().getLevel();

        List<ExportOrderVo> vos = new ArrayList<>();
        List<MmdOrder> orders = mmdOrderDao.orderList(eo);
        logger.info("导出admin订单列表 orders.size：{}",orders.size());
        for (MmdOrder order : orders) {
            List<MmdOrderDetailVo> detailList = mmdOrderDetailDao.list(order.getOrderNo());
            logger.info("导出admin订单列表 orderNo:{}, productList.size：{}",order.getOrderNo(),detailList.size());
            for (MmdOrderDetailVo mmdOrderDetailVo : detailList) {
                List<MmdOrderProduct> productList = mmdOrderProductDao.list(mmdOrderDetailVo.getPkgNo(), level);
                logger.info("导出admin订单列表 pkgNo:{}, productList.size：{}",mmdOrderDetailVo.getPkgNo(),productList.size());
                for (MmdOrderProduct mmdOrderProduct : productList) {
                    ExportOrderVo vo = new ExportOrderVo();
                    vo.setBatchNo(order.getBatchNo());
                    vo.setOrderNo(order.getOrderNo());
                    vo.setBoxNo(mmdOrderDetailVo.getBoxNo());
                    vo.setProductCnName(mmdOrderProduct.getProductCnName());
                    vo.setProductEnName(mmdOrderProduct.getProductEnName());
                    vo.setHsCode(mmdOrderProduct.getHsCode());
                    vo.setLength(mmdOrderDetailVo.getLength());
                    vo.setBreadth(mmdOrderDetailVo.getBreadth());
                    vo.setHeight(mmdOrderDetailVo.getHeight());
                    vo.setCount(mmdOrderProduct.getCount());
                    vo.setBulk(mmdOrderDetailVo.getLength().multiply(mmdOrderDetailVo.getBreadth()).multiply(mmdOrderDetailVo.getHeight()).setScale(2, BigDecimal.ROUND_UP));
                    vo.setWeight(mmdOrderDetailVo.getWeight());
                    vo.setUnitPrice(mmdOrderProduct.getUnitPrice());
                    vo.setMaterialCnName(mmdOrderProduct.getMaterialCnName() + "|" + mmdOrderProduct.getMaterialEnName());
                    vo.setUseCnName(mmdOrderProduct.getUseCnName() + "|" + mmdOrderProduct.getUseEnName());
                    vo.setType(mmdOrderProduct.getType());
                    vo.setBrand(mmdOrderProduct.getBrand());
                    vo.setFbaPostcode(order.getFbaPostcode());
                    vo.setFbaDepotNo(order.getFbaDepotNo());
                    vo.setFbaLinkman(order.getFbaLinkman());
                    vo.setFbaTel(order.getFbaTel());
                    vo.setFbaAddress(order.getFbaAddress());
                    vos.add(vo);
                }
            }
        }
        return vos;
    }

    /**
     * 设置sheet值
     *
     * @param sheet
     * @param orderList
     */
    private void setSheet(Sheet sheet, List<ExportOrderVo> orderList) {
        PrintSetup ps = sheet.getPrintSetup();
        ps.setLandscape(true);
        for (int i = 0; i < orderList.size(); i++) {
            ExportOrderVo vo = orderList.get(i);

            Row rowi = sheet.createRow(i + 1);
            Cell c0 = rowi.createCell(0);
            c0.setCellValue(vo.getBatchNo());

            Cell c1 = rowi.createCell(1);
            c1.setCellValue(vo.getOrderNo());

            Cell c2 = rowi.createCell(2);
            c2.setCellValue(vo.getBoxNo());

            Cell c3 = rowi.createCell(3);
            c3.setCellValue(vo.getProductCnName());

            Cell c4 = rowi.createCell(4);
            c4.setCellValue(vo.getProductEnName());

            Cell c5 = rowi.createCell(5);
            c5.setCellValue(vo.getHsCode());

            Cell c6 = rowi.createCell(6);
            c6.setCellValue(String.valueOf(vo.getLength()));

            Cell c7 = rowi.createCell(7);
            c7.setCellValue(String.valueOf(vo.getBreadth()));

            Cell c8 = rowi.createCell(8);
            c8.setCellValue(String.valueOf(vo.getHeight()));

            Cell c9 = rowi.createCell(9);
            c9.setCellValue(String.valueOf(vo.getCount()));

            Cell c10 = rowi.createCell(10);
            c10.setCellValue(String.valueOf(vo.getBulk()));

            Cell c11 = rowi.createCell(11);
            c11.setCellValue(String.valueOf(vo.getWeight()));

            Cell c12 = rowi.createCell(12);
            c12.setCellValue(String.valueOf(vo.getUnitPrice()));

            Cell c13 = rowi.createCell(13);
            c13.setCellValue(vo.getMaterialCnName());

            Cell c14 = rowi.createCell(14);
            c14.setCellValue(vo.getUseCnName());

            Cell c15 = rowi.createCell(15);
            c15.setCellValue(vo.getType());

            Cell c16 = rowi.createCell(16);
            c16.setCellValue(vo.getBrand());

            Cell c17 = rowi.createCell(17);
            c17.setCellValue(vo.getFbaPostcode());

            Cell c18 = rowi.createCell(18);
            c18.setCellValue(vo.getFbaDepotNo());

            Cell c19 = rowi.createCell(19);
            c19.setCellValue(vo.getFbaLinkman());

            Cell c20 = rowi.createCell(20);
            c20.setCellValue(vo.getFbaTel());

            Cell c21 = rowi.createCell(21);
            c21.setCellValue(vo.getFbaAddress());
        }
    }


    @Override
    @Transactional
    public boolean storage(String batchNo) {
        if (StringUtils.isBlank(batchNo)) {
            throw new GameException(new CODE(9999, "请勾选主订单"));
        }
        SuOrder suOrder = new SuOrder();
        suOrder.setStatus(StatusEnums.WAREHOUSING.getCode());
        suOrder.setBatchNo(batchNo);
        suOrderDao.updateByPrimaryKeySelective(suOrder);

        List<MmdOrder> orders = mmdOrderDao.listByBatchNo(batchNo);
        MmdOrder update = null;
        for (MmdOrder order : orders) {
            if (order.getStatus() < StatusEnums.WAREHOUSING.getCode()) {
                update = new MmdOrder();
                update.setOrderNo(order.getOrderNo());
                update.setStatus(StatusEnums.WAREHOUSING.getCode());
                mmdOrderDao.updateByPrimaryKeySelective(update);
            }
        }
        return true;
    }

    @Override
    @Transactional
    public boolean batchStorage(String batchNos) {
        if (StringUtils.isBlank(batchNos)) {
            throw new GameException(new CODE(9999, "请勾选主订单"));
        }
        List<String> batchNoList = Splitter.on(",").splitToList(batchNos);
        for (String batchNo : batchNoList) {
            this.storage(batchNo);
        }
        return false;
    }


    @Override
    @Transactional
    public void importTrackingFile(List<ImportTrackingBean> list) {
        MmdOrder updateOrder = null;
        for (ImportTrackingBean importTrackingBean : list) {
            List<MmdOrder> orders = mmdOrderDao.listByBatchNo(importTrackingBean.getBatchNo());
            if (!CollectionUtils.isEmpty(orders)) {
                for (MmdOrder order : orders) {
                    updateOrder = new MmdOrder();
                    updateOrder.setOrderNo(order.getOrderNo());
                    updateOrder.setLogisticsNo(importTrackingBean.getTrackingNo());
                    updateOrder.setLogisticsCompanyCode(importTrackingBean.getLogisticsCompanyCode());
                    KDniaoEnums statusEnum = KDniaoEnums.getStatusEnum(importTrackingBean.getLogisticsCompanyCode());
                    updateOrder.setLogisticsCompanyName(statusEnum == null ? "无" : statusEnum.getName());
                    updateOrder.setStatus(StatusEnums.DELIVERED.getCode());
                    mmdOrderDao.updateByPrimaryKeySelective(updateOrder);
                }
                SuOrder suOrder = new SuOrder();
                suOrder.setBatchNo(importTrackingBean.getBatchNo());
                suOrder.setStatus(StatusEnums.DELIVERED.getCode());
                suOrder.setTrackingNo(importTrackingBean.getTrackingNo());
                suOrderDao.updateByPrimaryKeySelective(suOrder);
            }
        }
    }


    @Override
    public SuOrderBoxDetailVo getSuBoxDetail(String batchNo) {
        SuOrder suOrder = suOrderDao.selectByPrimaryKey(batchNo);

        if (suOrder == null) {
            throw new GameException(new CODE(9999, "主订单不存在"));
        }
        SuOrderBoxDetailVo vo = new SuOrderBoxDetailVo();
        vo.setBatchNo(suOrder.getBatchNo());
        vo.setRouteName(suOrder.getRouteName());
        //获取渠道路线费用
        vo.setSingleDeclareFee(suOrder.getSingleDeclareFee());
        vo.setSingleOperatFee(suOrder.getSingleOperatFee());
        vo.setZgFee(suOrder.getZgFee());
        vo.setBackBoxRemark(suOrder.getBackBoxRemark());

        vo.setWeightSum(suOrder.getChargedWeight());
        vo.setTotalFee(suOrder.getTotalFee());
        vo.setAttachFee(suOrder.getAttachFee());
        if (Objects.equals(suOrder.getIscog(), YesNoEnums.NO.getCode())) {
            //非单独清关，需要把中港费、单独报关费返回0
            vo.setSingleDeclareFee(BigDecimal.ZERO);
            vo.setZgFee(BigDecimal.ZERO);
        }
        //整理箱单
        MmdRoute mmdRoute = mmdRouteDao.selectByPrimaryKey(suOrder.getRouteNo());
        List<SuOrderDetail> suOrderDetails = suOrderDetailDao.listByBatchNo(suOrder.getBatchNo());
        List<OrderBoxItemVo> itemVos = new ArrayList<>();
        for (SuOrderDetail detail : suOrderDetails) {
            OrderBoxItemVo itemVo = new OrderBoxItemVo();
            itemVo.setBoxNo(detail.getBoxNo());
            itemVo.setPkgNo(detail.getPkgNo());
            itemVo.setLength(detail.getLength());
            itemVo.setBreadth(detail.getBreadth());
            itemVo.setHeight(detail.getHeight());
            BigDecimal volume = BigDecimal.ZERO;

            if (mmdRoute.getModeId() == 5 || mmdRoute.getModeId() == 6) {
                volume = (detail.getLength().multiply(detail.getBreadth()).multiply(detail.getHeight())).divide(new BigDecimal(5000), 2, RoundingMode.HALF_UP);
            }else if (mmdRoute.getModeId() == 9) {
                volume = (detail.getLength().multiply(detail.getBreadth()).multiply(detail.getHeight())).divide(new BigDecimal(1000000), 3, RoundingMode.HALF_UP);
            }else {
                volume = (detail.getLength().multiply(detail.getBreadth()).multiply(detail.getHeight())).divide(new BigDecimal(6000), 2, RoundingMode.HALF_UP);
            }
            if (mmdRoute.getModeId() == 5 || mmdRoute.getModeId() == 6){
                volume = halfUp5(volume);
            }
            itemVo.setVolume(volume);
            itemVo.setWeight(detail.getWeight());
            BigDecimal jfz = (itemVo.getWeight()==null?BigDecimal.ZERO:itemVo.getWeight()).compareTo(volume==null?BigDecimal.ZERO:volume) == 1 ? itemVo.getWeight() : volume;
            //UPS的计费重要进半位
            if (mmdRoute.getModeId() == 5 || mmdRoute.getModeId() == 6){
                jfz = halfUp5(jfz);
            }

            jfz = getJfz(suOrder.getDestinationCountryId(), String.valueOf(mmdRoute.getModeId()), jfz);

            itemVo.setJfz(jfz);
            itemVos.add(itemVo);
        }
        vo.setChannelNo(String.valueOf(mmdRoute.getModeId()));
        vo.setItemVos(itemVos);
        return vo;
    }
}
